From 2811a8418774bb0002fb51333259878360547377 Mon Sep 17 00:00:00 2001 From: puvvadar Date: Thu, 30 Sep 2021 19:59:34 -0700 Subject: [PATCH 01/27] Move did handshake logic to connection data plus an optimization Signed-off-by: puvvadar --- .../AutoGen/AutoPacketDispatcher_Inline.jinja | 11 ++++++- .../ConnectionData/IConnectionData.h | 9 ++++++ .../ClientToServerConnectionData.h | 3 ++ .../ClientToServerConnectionData.inl | 10 ++++++ .../ServerToClientConnectionData.h | 3 ++ .../ServerToClientConnectionData.inl | 10 ++++++ .../Editor/MultiplayerEditorConnection.h | 1 - .../Source/MultiplayerSystemComponent.cpp | 31 ++++++++++++------- .../Code/Source/MultiplayerSystemComponent.h | 3 +- 9 files changed, 66 insertions(+), 15 deletions(-) diff --git a/Code/Framework/AzNetworking/AzNetworking/AutoGen/AutoPacketDispatcher_Inline.jinja b/Code/Framework/AzNetworking/AzNetworking/AutoGen/AutoPacketDispatcher_Inline.jinja index c6f1a23402..73c3227cd5 100644 --- a/Code/Framework/AzNetworking/AzNetworking/AutoGen/AutoPacketDispatcher_Inline.jinja +++ b/Code/Framework/AzNetworking/AzNetworking/AutoGen/AutoPacketDispatcher_Inline.jinja @@ -6,15 +6,24 @@ namespace {{ xml.attrib['Name'] }} { switch (aznumeric_cast(packetHeader.GetPacketType())) { +{% set hs = namespace(handshake=false) %} +{% for Packet in xml.iter('Packet') %} +{% if ('HandshakePacket' in Packet.attrib) and (Packet.attrib['HandshakePacket'] == 'true') %} +{% set hs.handshake = True %} +{% endif %} +{% endfor %} + {% for Packet in xml.iter('Packet') %} case aznumeric_cast({{ Packet.attrib['Name'] }}::Type): { AZLOG(Debug_DispatchPackets, "Received packet %s", "{{ Packet.attrib['Name'] }}"); +{% if hs.handshake %} {% if ('HandshakePacket' not in Packet.attrib) or (Packet.attrib['HandshakePacket'] == 'false') %} - if (!handler.IsHandshakeComplete()) + if (!handler.IsHandshakeComplete(connection)) { return AzNetworking::PacketDispatchResult::Skipped; } +{% endif %} {% endif %} {{ Packet.attrib['Name'] }} packet; diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/ConnectionData/IConnectionData.h b/Gems/Multiplayer/Code/Include/Multiplayer/ConnectionData/IConnectionData.h index 66a7a1175a..01914f55ae 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/ConnectionData/IConnectionData.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/ConnectionData/IConnectionData.h @@ -50,5 +50,14 @@ namespace Multiplayer //! Sets the state of connection whether update messages can be sent or not. //! @param canSendUpdates the state value virtual void SetCanSendUpdates(bool canSendUpdates) = 0; + + + //! Fetches the state of connection whether handshake logic has completed + //! @return true if handshake has completed + virtual bool DidHandshake() const = 0; + + //! Sets the state of connection whether handshake logic has completed + //! @param didHandshake if handshake logic has completed + virtual void SetDidHandshake(bool didHandshake) = 0; }; } diff --git a/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.h b/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.h index e5f1d0edfc..27826baf88 100644 --- a/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.h +++ b/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.h @@ -33,6 +33,8 @@ namespace Multiplayer void Update(AZ::TimeMs hostTimeMs) override; bool CanSendUpdates() const override; void SetCanSendUpdates(bool canSendUpdates) override; + bool DidHandshake() const override; + void SetDidHandshake(bool didHandshake) override; //! @} const AZStd::string& GetProviderTicket() const; @@ -43,6 +45,7 @@ namespace Multiplayer AZStd::string m_providerTicket; AzNetworking::IConnection* m_connection = nullptr; bool m_canSendUpdates = true; + bool m_didHandshake = false; }; } diff --git a/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.inl b/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.inl index 9d6a3ca744..8874fbbabc 100644 --- a/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.inl +++ b/Gems/Multiplayer/Code/Source/ConnectionData/ClientToServerConnectionData.inl @@ -27,4 +27,14 @@ namespace Multiplayer { m_providerTicket = ticket; } + + inline bool ClientToServerConnectionData::DidHandshake() const + { + return m_didHandshake; + } + + inline void ClientToServerConnectionData::SetDidHandshake(bool didHandshake) + { + m_didHandshake = didHandshake; + } } diff --git a/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.h b/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.h index 9e9afc4413..4e588570ec 100644 --- a/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.h +++ b/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.h @@ -33,6 +33,8 @@ namespace Multiplayer void Update(AZ::TimeMs hostTimeMs) override; bool CanSendUpdates() const override; void SetCanSendUpdates(bool canSendUpdates) override; + bool DidHandshake() const override; + void SetDidHandshake(bool didHandshake) override; //! @} NetworkEntityHandle GetPrimaryPlayerEntity(); @@ -52,6 +54,7 @@ namespace Multiplayer AZStd::string m_providerTicket; AzNetworking::IConnection* m_connection = nullptr; bool m_canSendUpdates = false; + bool m_didHandshake = false; }; } diff --git a/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.inl b/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.inl index 53ba51f36a..e4348fe539 100644 --- a/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.inl +++ b/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.inl @@ -38,4 +38,14 @@ namespace Multiplayer { m_providerTicket = ticket; } + + inline bool ServerToClientConnectionData::DidHandshake() const + { + return m_didHandshake; + } + + inline void ServerToClientConnectionData::SetDidHandshake(bool didHandshake) + { + m_didHandshake = didHandshake; + } } diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.h b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.h index ca815d5c48..b93c830cd0 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.h +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.h @@ -33,7 +33,6 @@ namespace Multiplayer MultiplayerEditorConnection(); ~MultiplayerEditorConnection() = default; - bool IsHandshakeComplete() const { return true; }; bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerEditorPackets::EditorServerInit& packet); bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerEditorPackets::EditorServerReady& packet); diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index 023c5ea3af..b1d80a87b5 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -442,9 +442,9 @@ namespace Multiplayer MultiplayerPackets::SyncConsole m_syncPacket; }; - bool MultiplayerSystemComponent::IsHandshakeComplete() const + bool MultiplayerSystemComponent::IsHandshakeComplete(AzNetworking::IConnection* connection) const { - return m_didHandshake; + return reinterpret_cast(connection->GetUserData())->DidHandshake(); } bool MultiplayerSystemComponent::HandleRequest @@ -471,7 +471,7 @@ namespace Multiplayer if (connection->SendReliablePacket(MultiplayerPackets::Accept(InvalidHostId, sv_map))) { - m_didHandshake = true; + reinterpret_cast(connection->GetUserData())->SetDidHandshake(true); // Sync our console ConsoleReplicator consoleReplicator(connection); @@ -488,7 +488,7 @@ namespace Multiplayer [[maybe_unused]] MultiplayerPackets::Accept& packet ) { - m_didHandshake = true; + reinterpret_cast(connection->GetUserData())->SetDidHandshake(true); AZ::CVarFixedString commandString = "sv_map " + packet.GetMap(); AZ::Interface::Get()->PerformCommand(commandString.c_str()); @@ -903,8 +903,9 @@ namespace Multiplayer // Unfortunately necessary, as NotifyPreRender can update transforms and thus cause a deadlock inside the vis system AZStd::vector gatheredEntities; + INetworkEntityManager* netEntityManager = GetNetworkEntityManager(); AZ::Interface::Get()->GetDefaultVisibilityScene()->Enumerate(viewFrustum, - [&gatheredEntities](const AzFramework::IVisibilityScene::NodeData& nodeData) + [netEntityManager, &gatheredEntities](const AzFramework::IVisibilityScene::NodeData& nodeData) { gatheredEntities.reserve(gatheredEntities.size() + nodeData.m_entries.size()); for (AzFramework::VisibilityEntry* visEntry : nodeData.m_entries) @@ -912,10 +913,14 @@ namespace Multiplayer if (visEntry->m_typeFlags & AzFramework::VisibilityEntry::TypeFlags::TYPE_Entity) { AZ::Entity* entity = static_cast(visEntry->m_userData); - NetBindComponent* netBindComponent = entity->FindComponent(); - if (netBindComponent != nullptr) + NetEntityId netEntitydId = netEntityManager->GetNetEntityIdById(entity->GetId()); + if (netEntitydId != InvalidNetEntityId) { - gatheredEntities.push_back(netBindComponent); + NetBindComponent* netBindComponent = netEntityManager->GetEntity(netEntitydId).GetNetBindComponent(); + if (netBindComponent != nullptr) + { + gatheredEntities.push_back(netBindComponent); + } } } } @@ -932,10 +937,14 @@ namespace Multiplayer for (auto& iter : *(m_networkEntityManager.GetNetworkEntityTracker())) { AZ::Entity* entity = iter.second; - NetBindComponent* netBindComponent = entity->FindComponent(); - if (netBindComponent != nullptr) + NetEntityId netEntitydId = GetNetworkEntityManager()->GetNetEntityIdById(entity->GetId()); + if (netEntitydId != InvalidNetEntityId) { - netBindComponent->NotifyPreRender(deltaTime); + NetBindComponent* netBindComponent = GetNetworkEntityManager()->GetEntity(netEntitydId).GetNetBindComponent(); + if (netBindComponent != nullptr) + { + netBindComponent->NotifyPreRender(deltaTime); + } } } } diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h index c467ed9ad9..ad9f22bc5b 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h @@ -76,7 +76,7 @@ namespace Multiplayer int GetTickOrder() override; //! @} - bool IsHandshakeComplete() const; + bool IsHandshakeComplete(AzNetworking::IConnection* connection) const; bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::Connect& packet); bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::Accept& packet); bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::ReadyForEntityUpdates& packet); @@ -159,7 +159,6 @@ namespace Multiplayer double m_serverSendAccumulator = 0.0; float m_renderBlendFactor = 0.0f; float m_tickFactor = 0.0f; - bool m_didHandshake = false; #if !defined(AZ_RELEASE_BUILD) MultiplayerEditorConnection m_editorConnectionListener; From f6638420f09fb6ca97b0b47962c201d08aeb020f Mon Sep 17 00:00:00 2001 From: puvvadar Date: Thu, 30 Sep 2021 20:02:38 -0700 Subject: [PATCH 02/27] Formatting fix up Signed-off-by: puvvadar --- .../AutoGen/AutoPacketDispatcher_Inline.jinja | 16 ++++++++-------- .../Multiplayer/ConnectionData/IConnectionData.h | 1 - 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Code/Framework/AzNetworking/AzNetworking/AutoGen/AutoPacketDispatcher_Inline.jinja b/Code/Framework/AzNetworking/AzNetworking/AutoGen/AutoPacketDispatcher_Inline.jinja index 73c3227cd5..a621af92cb 100644 --- a/Code/Framework/AzNetworking/AzNetworking/AutoGen/AutoPacketDispatcher_Inline.jinja +++ b/Code/Framework/AzNetworking/AzNetworking/AutoGen/AutoPacketDispatcher_Inline.jinja @@ -6,25 +6,25 @@ namespace {{ xml.attrib['Name'] }} { switch (aznumeric_cast(packetHeader.GetPacketType())) { -{% set hs = namespace(handshake=false) %} +{% set packet_ns = namespace(handshake=false) %} {% for Packet in xml.iter('Packet') %} -{% if ('HandshakePacket' in Packet.attrib) and (Packet.attrib['HandshakePacket'] == 'true') %} -{% set hs.handshake = True %} -{% endif %} +{% if ('HandshakePacket' in Packet.attrib) and (Packet.attrib['HandshakePacket'] == 'true') %} +{% set packet_ns.handshake = True %} +{% endif %} {% endfor %} {% for Packet in xml.iter('Packet') %} case aznumeric_cast({{ Packet.attrib['Name'] }}::Type): { AZLOG(Debug_DispatchPackets, "Received packet %s", "{{ Packet.attrib['Name'] }}"); -{% if hs.handshake %} -{% if ('HandshakePacket' not in Packet.attrib) or (Packet.attrib['HandshakePacket'] == 'false') %} +{% if packet_ns.handshake %} +{% if ('HandshakePacket' not in Packet.attrib) or (Packet.attrib['HandshakePacket'] == 'false') %} if (!handler.IsHandshakeComplete(connection)) { return AzNetworking::PacketDispatchResult::Skipped; } -{% endif %} -{% endif %} +{% endif %} +{% endif %} {{ Packet.attrib['Name'] }} packet; if (!serializer.Serialize(packet, "Packet")) diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/ConnectionData/IConnectionData.h b/Gems/Multiplayer/Code/Include/Multiplayer/ConnectionData/IConnectionData.h index 01914f55ae..90dfcc16bd 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/ConnectionData/IConnectionData.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/ConnectionData/IConnectionData.h @@ -51,7 +51,6 @@ namespace Multiplayer //! @param canSendUpdates the state value virtual void SetCanSendUpdates(bool canSendUpdates) = 0; - //! Fetches the state of connection whether handshake logic has completed //! @return true if handshake has completed virtual bool DidHandshake() const = 0; From 0a6ddfab5efd24ab232105927f04200a393debeb Mon Sep 17 00:00:00 2001 From: puvvadar Date: Fri, 1 Oct 2021 11:02:12 -0700 Subject: [PATCH 03/27] Revert optimization change in favor of another PR Signed-off-by: puvvadar --- .../Source/MultiplayerSystemComponent.cpp | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index b1d80a87b5..71e8b04d85 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -903,9 +903,8 @@ namespace Multiplayer // Unfortunately necessary, as NotifyPreRender can update transforms and thus cause a deadlock inside the vis system AZStd::vector gatheredEntities; - INetworkEntityManager* netEntityManager = GetNetworkEntityManager(); AZ::Interface::Get()->GetDefaultVisibilityScene()->Enumerate(viewFrustum, - [netEntityManager, &gatheredEntities](const AzFramework::IVisibilityScene::NodeData& nodeData) + [&gatheredEntities](const AzFramework::IVisibilityScene::NodeData& nodeData) { gatheredEntities.reserve(gatheredEntities.size() + nodeData.m_entries.size()); for (AzFramework::VisibilityEntry* visEntry : nodeData.m_entries) @@ -913,14 +912,10 @@ namespace Multiplayer if (visEntry->m_typeFlags & AzFramework::VisibilityEntry::TypeFlags::TYPE_Entity) { AZ::Entity* entity = static_cast(visEntry->m_userData); - NetEntityId netEntitydId = netEntityManager->GetNetEntityIdById(entity->GetId()); - if (netEntitydId != InvalidNetEntityId) + NetBindComponent* netBindComponent = entity->FindComponent(); + if (netBindComponent != nullptr) { - NetBindComponent* netBindComponent = netEntityManager->GetEntity(netEntitydId).GetNetBindComponent(); - if (netBindComponent != nullptr) - { - gatheredEntities.push_back(netBindComponent); - } + gatheredEntities.push_back(netBindComponent); } } } @@ -937,14 +932,10 @@ namespace Multiplayer for (auto& iter : *(m_networkEntityManager.GetNetworkEntityTracker())) { AZ::Entity* entity = iter.second; - NetEntityId netEntitydId = GetNetworkEntityManager()->GetNetEntityIdById(entity->GetId()); - if (netEntitydId != InvalidNetEntityId) + NetBindComponent* netBindComponent = entity->FindComponent(); + if (netBindComponent != nullptr) { - NetBindComponent* netBindComponent = GetNetworkEntityManager()->GetEntity(netEntitydId).GetNetBindComponent(); - if (netBindComponent != nullptr) - { - netBindComponent->NotifyPreRender(deltaTime); - } + netBindComponent->NotifyPreRender(deltaTime); } } } From a18655e8f7305f05844170adfce2ee0a574cf832 Mon Sep 17 00:00:00 2001 From: puvvadar Date: Fri, 1 Oct 2021 11:43:22 -0700 Subject: [PATCH 04/27] Update jinja change to use booleanTrue filter Signed-off-by: puvvadar --- .../AzNetworking/AutoGen/AutoPacketDispatcher_Inline.jinja | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzNetworking/AzNetworking/AutoGen/AutoPacketDispatcher_Inline.jinja b/Code/Framework/AzNetworking/AzNetworking/AutoGen/AutoPacketDispatcher_Inline.jinja index a621af92cb..145f15bb19 100644 --- a/Code/Framework/AzNetworking/AzNetworking/AutoGen/AutoPacketDispatcher_Inline.jinja +++ b/Code/Framework/AzNetworking/AzNetworking/AutoGen/AutoPacketDispatcher_Inline.jinja @@ -8,7 +8,7 @@ namespace {{ xml.attrib['Name'] }} { {% set packet_ns = namespace(handshake=false) %} {% for Packet in xml.iter('Packet') %} -{% if ('HandshakePacket' in Packet.attrib) and (Packet.attrib['HandshakePacket'] == 'true') %} +{% if ('HandshakePacket' in Packet.attrib) and (Packet.attrib['HandshakePacket']|booleanTrue == true) %} {% set packet_ns.handshake = True %} {% endif %} {% endfor %} From 1245c2361d769bd777255400660caff958a151af Mon Sep 17 00:00:00 2001 From: Mike Cronin <58789750+micronAMZN@users.noreply.github.com> Date: Fri, 1 Oct 2021 16:06:11 -0700 Subject: [PATCH 05/27] Updated documentation_url field. This doc is being moved per: https://github.com/o3de/o3de.org/pull/993 Signed-off-by: Mike Cronin <58789750+micronAMZN@users.noreply.github.com> --- Gems/LmbrCentral/gem.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/LmbrCentral/gem.json b/Gems/LmbrCentral/gem.json index 36de4c4ed3..9fca421538 100644 --- a/Gems/LmbrCentral/gem.json +++ b/Gems/LmbrCentral/gem.json @@ -15,6 +15,6 @@ ], "icon_path": "preview.png", "requirements": "", - "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/core/lmbr-central/", + "documentation_url": "https://o3de.org/docs/user-guide/gems/reference/o3de-core/", "dependencies": [] } From 3321f9e5eaa131d6738d0e7410f4d127dc42fb94 Mon Sep 17 00:00:00 2001 From: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> Date: Mon, 4 Oct 2021 09:00:20 -0400 Subject: [PATCH 06/27] First google benchmarks for hierarchy logic. Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> --- Gems/Multiplayer/Code/CMakeLists.txt | 4 + .../Multiplayer/Components/NetBindComponent.h | 1 + .../NetworkHierarchyRootComponent.h | 2 + .../Code/Tests/CommonBenchmarkSetup.h | 640 ++++++++++++++++++ .../Code/Tests/ServerHierarchyBenchmarks.cpp | 118 ++++ .../Code/multiplayer_tests_files.cmake | 2 + 6 files changed, 767 insertions(+) create mode 100644 Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h create mode 100644 Gems/Multiplayer/Code/Tests/ServerHierarchyBenchmarks.cpp diff --git a/Gems/Multiplayer/Code/CMakeLists.txt b/Gems/Multiplayer/Code/CMakeLists.txt index 49b404fb1c..909590a25d 100644 --- a/Gems/Multiplayer/Code/CMakeLists.txt +++ b/Gems/Multiplayer/Code/CMakeLists.txt @@ -179,6 +179,10 @@ if (PAL_TRAIT_BUILD_TESTS_SUPPORTED) ly_add_googletest( NAME Gem::Multiplayer.Tests ) + ly_add_googlebenchmark( + NAME Gem::Multiplayer.Benchmarks + TARGET Gem::Multiplayer.Tests + ) if (PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetBindComponent.h b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetBindComponent.h index 743315e8bc..eea4a259f4 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetBindComponent.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetBindComponent.h @@ -201,6 +201,7 @@ namespace Multiplayer friend class EntityReplicationManager; friend class HierarchyTests; + friend class HierarchyBenchmarkBase; }; bool NetworkRoleHasController(NetEntityRole networkRole); diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkHierarchyRootComponent.h b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkHierarchyRootComponent.h index 4c9f94c004..674dc6114d 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkHierarchyRootComponent.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkHierarchyRootComponent.h @@ -96,5 +96,7 @@ namespace Multiplayer //! Set to false when deactivating or otherwise not to be included in hierarchy considerations. bool m_isHierarchyEnabled = true; + + friend class HierarchyBenchmarkBase; }; } diff --git a/Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h b/Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h new file mode 100644 index 0000000000..e0018e2f26 --- /dev/null +++ b/Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h @@ -0,0 +1,640 @@ +/* + * 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 + +#ifdef HAVE_BENCHMARK +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Multiplayer +{ + class BenchmarkComponentApplicationRequests : public AZ::ComponentApplicationRequests + { + public: + void RegisterComponentDescriptor([[maybe_unused]] const AZ::ComponentDescriptor* descriptor) override {} + void UnregisterComponentDescriptor([[maybe_unused]] const AZ::ComponentDescriptor* descriptor) override {} + AZ::ComponentApplication* GetApplication() override { return {}; } + void RegisterEntityAddedEventHandler([[maybe_unused]] AZ::Event::Handler& handler) override {} + void RegisterEntityRemovedEventHandler([[maybe_unused]] AZ::Event::Handler& handler) override {} + void RegisterEntityActivatedEventHandler([[maybe_unused]] AZ::Event::Handler& handler) override {} + void RegisterEntityDeactivatedEventHandler([[maybe_unused]] AZ::Event::Handler& handler) override {} + void SignalEntityActivated([[maybe_unused]] AZ::Entity* entity) override {} + void SignalEntityDeactivated([[maybe_unused]] AZ::Entity* entity) override {} + bool RemoveEntity([[maybe_unused]] AZ::Entity* entity) override { return {}; } + bool DeleteEntity([[maybe_unused]] const AZ::EntityId& id) override { return {}; } + void EnumerateEntities([[maybe_unused]] const EntityCallback& callback) override {} + AZ::SerializeContext* GetSerializeContext() override { return {}; } + AZ::BehaviorContext* GetBehaviorContext() override { return {}; } + AZ::JsonRegistrationContext* GetJsonRegistrationContext() override { return {}; } + const char* GetAppRoot() const override { return {}; } + const char* GetEngineRoot() const override { return {}; } + const char* GetExecutableFolder() const override { return {}; } + void QueryApplicationType([[maybe_unused]] AZ::ApplicationTypeQuery& appType) const override {} + + AZStd::map m_entities; + + bool AddEntity(AZ::Entity* entity) override + { + m_entities[entity->GetId()] = entity; + return true; + } + + AZ::Entity* FindEntity(const AZ::EntityId& id) override + { + const auto iterator = m_entities.find(id); + if (iterator != m_entities.end()) + { + return iterator->second; + } + + return nullptr; + } + }; + + + class BenchmarkConnectionListener : public AzNetworking::IConnectionListener + { + public: + ConnectResult ValidateConnect([[maybe_unused]] const IpAddress& remoteAddress, [[maybe_unused]] const IPacketHeader& packetHeader, [[maybe_unused]] ISerializer& serializer) override + { + return {}; + } + + void OnConnect([[maybe_unused]] IConnection* connection) override + { + } + + PacketDispatchResult OnPacketReceived([[maybe_unused]] IConnection* connection, [[maybe_unused]] const IPacketHeader& packetHeader, [[maybe_unused]] ISerializer& serializer) override + { + return {}; + } + + void OnPacketLost([[maybe_unused]] IConnection* connection, [[maybe_unused]] PacketId packetId) override + { + } + + void OnDisconnect([[maybe_unused]] IConnection* connection, [[maybe_unused]] DisconnectReason reason, [[maybe_unused]] TerminationEndpoint endpoint) override + { + } + }; + + class BenchmarkTime : public AZ::ITime + { + public: + AZ::TimeMs GetElapsedTimeMs() const override + { + return {}; + } + }; + + class BenchmarkNetworkTime : public Multiplayer::INetworkTime + { + public: + bool IsTimeRewound() const override + { + return false; + } + + HostFrameId GetHostFrameId() const override + { + return {}; + } + + HostFrameId GetUnalteredHostFrameId() const override + { + return {}; + } + + void IncrementHostFrameId() override + { + } + + AZ::TimeMs GetHostTimeMs() const override + { + return {}; + } + + float GetHostBlendFactor() const override + { + return 0; + } + + AzNetworking::ConnectionId GetRewindingConnectionId() const override + { + return {}; + } + + void ForceSetTime([[maybe_unused]] HostFrameId frameId, [[maybe_unused]] AZ::TimeMs timeMs) override + { + } + + void SyncEntitiesToRewindState([[maybe_unused]] const AZ::Aabb& rewindVolume) override + { + } + + void ClearRewoundEntities() override + { + } + + void AlterTime([[maybe_unused]] HostFrameId frameId, [[maybe_unused]] AZ::TimeMs timeMs, [[maybe_unused]] float blendFactor, [[maybe_unused]] AzNetworking::ConnectionId rewindConnectionId) override + { + } + }; + + class BenchmarkMultiplayerConnection : public IConnection + { + public: + BenchmarkMultiplayerConnection(ConnectionId connectionId, const IpAddress& address, [[maybe_unused]] ConnectionRole connectionRole) + : IConnection(connectionId, address) + { + ; + } + + ~BenchmarkMultiplayerConnection() override = default; + + bool SendReliablePacket([[maybe_unused]] const IPacket& packet) override + { + return false; + } + + PacketId SendUnreliablePacket([[maybe_unused]] const IPacket& packet) override + { + return {}; + } + + bool WasPacketAcked([[maybe_unused]] PacketId packetId) const override + { + return false; + } + + ConnectionState GetConnectionState() const override + { + return {}; + } + + ConnectionRole GetConnectionRole() const override + { + return {}; + } + + bool Disconnect([[maybe_unused]] DisconnectReason reason, [[maybe_unused]] TerminationEndpoint endpoint) override + { + return false; + } + + void SetConnectionMtu([[maybe_unused]] uint32_t connectionMtu) override + { + } + + uint32_t GetConnectionMtu() const override + { + return 0; + } + }; + + class BenchmarkNetworkEntityManager : public Multiplayer::INetworkEntityManager + { + public: + BenchmarkNetworkEntityManager() : m_authorityTracker(*this) {} + + NetworkEntityTracker* GetNetworkEntityTracker() override { return &m_tracker; } + NetworkEntityAuthorityTracker* GetNetworkEntityAuthorityTracker() override { return &m_authorityTracker; } + MultiplayerComponentRegistry* GetMultiplayerComponentRegistry() override { return &m_multiplayerComponentRegistry; } + HostId GetHostId() const override { return {}; } + EntityList CreateEntitiesImmediate( + [[maybe_unused]] const PrefabEntityId& prefabEntryId, + [[maybe_unused]] NetEntityRole netEntityRole, + [[maybe_unused]] const AZ::Transform& transform, + [[maybe_unused]] AutoActivate autoActivate) override { + return {}; + } + EntityList CreateEntitiesImmediate( + [[maybe_unused]] const PrefabEntityId& prefabEntryId, + [[maybe_unused]] NetEntityId netEntityId, + [[maybe_unused]] NetEntityRole netEntityRole, + [[maybe_unused]] AutoActivate autoActivate, + [[maybe_unused]] const AZ::Transform& transform) override { + return {}; + } + void SetupNetEntity( + [[maybe_unused]] AZ::Entity* netEntity, + [[maybe_unused]] PrefabEntityId prefabEntityId, + [[maybe_unused]] NetEntityRole netEntityRole) override {} + uint32_t GetEntityCount() const override { return {}; } + void MarkForRemoval( + [[maybe_unused]] const ConstNetworkEntityHandle& entityHandle) override {} + bool IsMarkedForRemoval( + [[maybe_unused]] const ConstNetworkEntityHandle& entityHandle) const override { + return {}; + } + void ClearEntityFromRemovalList( + [[maybe_unused]] const ConstNetworkEntityHandle& entityHandle) override {} + void ClearAllEntities() override {} + void AddEntityMarkedDirtyHandler( + [[maybe_unused]] AZ::Event<>::Handler& entityMarkedDirtyHandle) override {} + void AddEntityNotifyChangesHandler( + [[maybe_unused]] AZ::Event<>::Handler& entityNotifyChangesHandle) override {} + void AddEntityExitDomainHandler( + [[maybe_unused]] EntityExitDomainEvent::Handler& entityExitDomainHandler) override {} + void AddControllersActivatedHandler( + [[maybe_unused]] ControllersActivatedEvent::Handler& controllersActivatedHandler) override {} + void AddControllersDeactivatedHandler( + [[maybe_unused]] ControllersDeactivatedEvent::Handler& controllersDeactivatedHandler) override {} + void NotifyEntitiesDirtied() override {} + void NotifyEntitiesChanged() override {} + void NotifyControllersActivated( + [[maybe_unused]] const ConstNetworkEntityHandle& entityHandle, + [[maybe_unused]] EntityIsMigrating entityIsMigrating) override {} + void NotifyControllersDeactivated( + [[maybe_unused]] const ConstNetworkEntityHandle& entityHandle, + [[maybe_unused]] EntityIsMigrating entityIsMigrating) override {} + void HandleLocalRpcMessage( + [[maybe_unused]] NetworkEntityRpcMessage& message) override {} + + mutable AZStd::map m_networkEntityMap; + + NetworkEntityHandle AddEntityToEntityMap(NetEntityId netEntityId, AZ::Entity* entity) override + { + m_networkEntityMap[netEntityId] = entity; + return NetworkEntityHandle(entity, netEntityId, &m_tracker); + } + + ConstNetworkEntityHandle GetEntity(NetEntityId netEntityId) const override + { + AZ::Entity* entity = m_networkEntityMap[netEntityId]; + return ConstNetworkEntityHandle(entity, &m_tracker); + } + + NetEntityId GetNetEntityIdById(const AZ::EntityId& entityId) const override + { + for (const auto& pair : m_networkEntityMap) + { + if (pair.second->GetId() == entityId) + { + return pair.first; + } + } + + return InvalidNetEntityId; + } + + [[nodiscard]] AZStd::unique_ptr RequestNetSpawnableInstantiation( + [[maybe_unused]] const AZ::Data::Asset& netSpawnable, + [[maybe_unused]] const AZ::Transform& transform) override + { + return {}; + } + + NetworkEntityTracker m_tracker; + NetworkEntityAuthorityTracker m_authorityTracker; + MultiplayerComponentRegistry m_multiplayerComponentRegistry; + }; + + class BenchmarkMultiplayer : public Multiplayer::IMultiplayer + { + public: + BenchmarkMultiplayer(BenchmarkNetworkEntityManager& manager) : m_manager(manager) {} + + MultiplayerAgentType GetAgentType() const override { return {}; } + void InitializeMultiplayer([[maybe_unused]] MultiplayerAgentType state) override {} + bool StartHosting([[maybe_unused]] uint16_t port, [[maybe_unused]] bool isDedicated) override { return {}; } + bool Connect([[maybe_unused]] AZStd::string remoteAddress, [[maybe_unused]] uint16_t port) override { return {}; } + void Terminate([[maybe_unused]] AzNetworking::DisconnectReason reason) override {} + void AddClientDisconnectedHandler([[maybe_unused]] ClientDisconnectedEvent::Handler& handler) override {} + void AddConnectionAcquiredHandler([[maybe_unused]] ConnectionAcquiredEvent::Handler& handler) override {} + void AddSessionInitHandler([[maybe_unused]] SessionInitEvent::Handler& handler) override {} + void AddSessionShutdownHandler([[maybe_unused]] SessionShutdownEvent::Handler& handler) override {} + void SendReadyForEntityUpdates([[maybe_unused]] bool readyForEntityUpdates) override {} + AZ::TimeMs GetCurrentHostTimeMs() const override { return {}; } + float GetCurrentBlendFactor() const override { return {}; } + INetworkTime* GetNetworkTime() override { return {}; } + INetworkEntityManager* GetNetworkEntityManager() override { return &m_manager; } + void SetFilterEntityManager([[maybe_unused]] IFilterEntityManager* entityFilter) override {} + IFilterEntityManager* GetFilterEntityManager() override { return {}; } + + BenchmarkNetworkEntityManager& m_manager; + }; + + class HierarchyBenchmarkBase + : public benchmark::Fixture + , public AllocatorsBase + { + public: + void SetUp(const benchmark::State&) override + { + internalSetUp(); + } + void SetUp(benchmark::State&) override + { + internalSetUp(); + } + + void TearDown(const benchmark::State&) override + { + internalTearDown(); + } + void TearDown(benchmark::State&) override + { + internalTearDown(); + } + + virtual void internalSetUp() + { + SetupAllocator(); + AZ::NameDictionary::Create(); + + m_ComponentApplicationRequests = AZStd::make_unique(); + AZ::Interface::Register(m_ComponentApplicationRequests.get()); + + // register components involved in testing + m_serializeContext = AZStd::make_unique(); + + m_transformDescriptor.reset(AzFramework::TransformComponent::CreateDescriptor()); + m_transformDescriptor->Reflect(m_serializeContext.get()); + + m_netBindDescriptor.reset(NetBindComponent::CreateDescriptor()); + m_netBindDescriptor->Reflect(m_serializeContext.get()); + + m_hierarchyRootDescriptor.reset(NetworkHierarchyRootComponent::CreateDescriptor()); + m_hierarchyRootDescriptor->Reflect(m_serializeContext.get()); + + m_hierarchyChildDescriptor.reset(NetworkHierarchyChildComponent::CreateDescriptor()); + m_hierarchyChildDescriptor->Reflect(m_serializeContext.get()); + + m_netTransformDescriptor.reset(NetworkTransformComponent::CreateDescriptor()); + m_netTransformDescriptor->Reflect(m_serializeContext.get()); + + m_NetworkEntityManager = AZStd::make_unique(); + + m_Multiplayer = AZStd::make_unique(*m_NetworkEntityManager); + AZ::Interface::Register(m_Multiplayer.get()); + + // Create space for replication stats + // Without Multiplayer::RegisterMultiplayerComponents() the stats go to invalid id, which is fine for unit tests + GetMultiplayer()->GetStats().ReserveComponentStats(Multiplayer::InvalidNetComponentId, 50, 0); + + m_Time = AZStd::make_unique(); + AZ::Interface::Register(m_Time.get()); + + m_NetworkTime = AZStd::make_unique(); + AZ::Interface::Register(m_NetworkTime.get()); + + EXPECT_NE(AZ::Interface::Get()->GetNetworkEntityManager(), nullptr); + + const IpAddress address("localhost", 1, ProtocolType::Udp); + m_Connection = AZStd::make_unique(ConnectionId{ 1 }, address, ConnectionRole::Connector); + m_ConnectionListener = AZStd::make_unique(); + + m_entityReplicationManager = AZStd::make_unique(*m_Connection, *m_ConnectionListener, EntityReplicationManager::Mode::LocalClientToRemoteServer); + + m_console.reset(aznew AZ::Console()); + AZ::Interface::Register(m_console.get()); + m_console->LinkDeferredFunctors(AZ::ConsoleFunctorBase::GetDeferredHead()); + + RegisterMultiplayerComponents(); + } + + virtual void internalTearDown() + { + AZ::Interface::Unregister(m_console.get()); + m_console.reset(); + + m_entityReplicationManager.reset(); + + m_Connection.reset(); + m_ConnectionListener.reset(); + + AZ::Interface::Unregister(m_NetworkTime.get()); + AZ::Interface::Unregister(m_Time.get()); + AZ::Interface::Unregister(m_Multiplayer.get()); + AZ::Interface::Unregister(m_ComponentApplicationRequests.get()); + + m_Time.reset(); + + m_NetworkEntityManager.reset(); + m_Multiplayer.reset(); + + m_transformDescriptor.reset(); + m_netTransformDescriptor.reset(); + m_hierarchyRootDescriptor.reset(); + m_hierarchyChildDescriptor.reset(); + m_netBindDescriptor.reset(); + m_serializeContext.reset(); + m_ComponentApplicationRequests.reset(); + + AZ::NameDictionary::Destroy(); + TeardownAllocator(); + } + + AZStd::unique_ptr m_console; + + AZStd::unique_ptr m_ComponentApplicationRequests; + AZStd::unique_ptr m_serializeContext; + AZStd::unique_ptr m_transformDescriptor; + AZStd::unique_ptr m_netBindDescriptor; + AZStd::unique_ptr m_hierarchyRootDescriptor; + AZStd::unique_ptr m_hierarchyChildDescriptor; + AZStd::unique_ptr m_netTransformDescriptor; + + AZStd::unique_ptr m_Multiplayer; + AZStd::unique_ptr m_NetworkEntityManager; + AZStd::unique_ptr m_Time; + AZStd::unique_ptr m_NetworkTime; + + AZStd::unique_ptr m_Connection; + AZStd::unique_ptr m_ConnectionListener; + + AZStd::unique_ptr m_entityReplicationManager; + + void SetupEntity(const AZStd::unique_ptr& entity, NetEntityId netId, NetEntityRole role) + { + const auto netBindComponent = entity->FindComponent(); + EXPECT_NE(netBindComponent, nullptr); + netBindComponent->PreInit(entity.get(), PrefabEntityId{ AZ::Name("test"), 1 }, netId, role); + entity->Init(); + } + + static void StopEntity(const AZStd::unique_ptr& entity) + { + const auto netBindComponent = entity->FindComponent(); + EXPECT_NE(netBindComponent, nullptr); + netBindComponent->StopEntity(); + } + + static void StopAndDeactivateEntity(AZStd::unique_ptr& entity) + { + if (entity) + { + StopEntity(entity); + entity->Deactivate(); + entity.reset(); + } + } + + void CreateEntityWithRootHierarchy(AZStd::unique_ptr& rootEntity) + { + rootEntity->CreateComponent(); + rootEntity->CreateComponent(); + rootEntity->CreateComponent(); + rootEntity->CreateComponent(); + } + + void CreateEntityWithChildHierarchy(AZStd::unique_ptr& childEntity) + { + childEntity->CreateComponent(); + childEntity->CreateComponent(); + childEntity->CreateComponent(); + childEntity->CreateComponent(); + } + + void SetParentIdOnNetworkTransform(const AZStd::unique_ptr& entity, NetEntityId netParentId) + { + /* Derived from NetworkTransformComponent.AutoComponent.xml */ + constexpr int totalBits = 6 /*NetworkTransformComponentInternal::AuthorityToClientDirtyEnum::Count*/; + constexpr int parentIdBit = 4 /*NetworkTransformComponentInternal::AuthorityToClientDirtyEnum::parentEntityId_DirtyFlag*/; + + ReplicationRecord currentRecord; + currentRecord.m_authorityToClient.AddBits(totalBits); + currentRecord.m_authorityToClient.SetBit(parentIdBit, true); + + constexpr uint32_t bufferSize = 100; + AZStd::array buffer = {}; + NetworkInputSerializer inSerializer(buffer.begin(), bufferSize); + inSerializer.Serialize(reinterpret_cast(netParentId), + "parentEntityId", /* Derived from NetworkTransformComponent.AutoComponent.xml */ + AZStd::numeric_limits::min(), AZStd::numeric_limits::max()); + + NetworkOutputSerializer outSerializer(buffer.begin(), bufferSize); + + ReplicationRecord notifyRecord = currentRecord; + entity->FindComponent()->SerializeStateDeltaMessage(currentRecord, outSerializer); + entity->FindComponent()->NotifyStateDeltaChanges(notifyRecord); + } + + template + void SetHierarchyRootFieldOnNetworkHierarchyChild(const AZStd::unique_ptr& entity, NetEntityId value) + { + /* Derived from NetworkHierarchyChildComponent.AutoComponent.xml */ + constexpr int totalBits = 1 /*NetworkHierarchyChildComponentInternal::AuthorityToClientDirtyEnum::Count*/; + constexpr int inHierarchyBit = 0 /*NetworkHierarchyChildComponentInternal::AuthorityToClientDirtyEnum::hierarchyRoot_DirtyFlag*/; + + ReplicationRecord currentRecord; + currentRecord.m_authorityToClient.AddBits(totalBits); + currentRecord.m_authorityToClient.SetBit(inHierarchyBit, true); + + constexpr uint32_t bufferSize = 100; + AZStd::array buffer = {}; + NetworkInputSerializer inSerializer(buffer.begin(), bufferSize); + inSerializer.Serialize(reinterpret_cast(value), + "hierarchyRoot", /* Derived from NetworkHierarchyChildComponent.AutoComponent.xml */ + AZStd::numeric_limits::min(), AZStd::numeric_limits::max()); + + NetworkOutputSerializer outSerializer(buffer.begin(), bufferSize); + + ReplicationRecord notifyRecord = currentRecord; + entity->FindComponent()->SerializeStateDeltaMessage(currentRecord, outSerializer); + entity->FindComponent()->NotifyStateDeltaChanges(notifyRecord); + } + + struct EntityInfo + { + enum class Role + { + Root, + Child, + None + }; + + EntityInfo(AZ::u64 entityId, const char* entityName, NetEntityId netId, Role role) + : m_entity(AZStd::make_unique(AZ::EntityId(entityId), entityName)) + , m_netId(netId) + , m_role(role) + { + } + + ~EntityInfo() + { + StopAndDeactivateEntity(m_entity); + } + + AZStd::unique_ptr m_entity; + NetEntityId m_netId; + AZStd::unique_ptr m_replicator; + Role m_role = Role::None; + }; + + void PopulateHierarchicalEntity(const EntityInfo& entityInfo) + { + entityInfo.m_entity->CreateComponent(); + entityInfo.m_entity->CreateComponent(); + entityInfo.m_entity->CreateComponent(); + switch (entityInfo.m_role) + { + case EntityInfo::Role::Root: + entityInfo.m_entity->CreateComponent(); + break; + case EntityInfo::Role::Child: + entityInfo.m_entity->CreateComponent(); + break; + case EntityInfo::Role::None: + break; + } + } + + void CreateParent(EntityInfo& parent) + { + PopulateHierarchicalEntity(parent); + + SetupEntity(parent.m_entity, parent.m_netId, NetEntityRole::Authority); + + // Create an entity replicator for the child entity + const NetworkEntityHandle childHandle(parent.m_entity.get(), m_NetworkEntityManager->GetNetworkEntityTracker()); + parent.m_replicator = AZStd::make_unique(*m_entityReplicationManager, m_Connection.get(), NetEntityRole::Client, childHandle); + parent.m_replicator->Initialize(childHandle); + + parent.m_entity->Activate(); + } + + void CreateChildForParent(EntityInfo& child, EntityInfo& parent) + { + PopulateHierarchicalEntity(child); + + SetupEntity(child.m_entity, child.m_netId, NetEntityRole::Authority); + + // we need a parent-id value to be present in NetworkTransformComponent (which is in client mode and doesn't have a controller) + SetParentIdOnNetworkTransform(child.m_entity, parent.m_netId); + + // Create an entity replicator for the child entity + const NetworkEntityHandle childHandle(child.m_entity.get(), m_NetworkEntityManager->GetNetworkEntityTracker()); + child.m_replicator = AZStd::make_unique(*m_entityReplicationManager, m_Connection.get(), NetEntityRole::Client, childHandle); + child.m_replicator->Initialize(childHandle); + + child.m_entity->Activate(); + } + + void ForceRebuildHierarchy(const AZStd::unique_ptr& rootEntity) + { + if (NetworkHierarchyRootComponent* root = rootEntity->FindComponent()) + { + root->RebuildHierarchy(); + } + } + }; +} + +#endif diff --git a/Gems/Multiplayer/Code/Tests/ServerHierarchyBenchmarks.cpp b/Gems/Multiplayer/Code/Tests/ServerHierarchyBenchmarks.cpp new file mode 100644 index 0000000000..6a404bfa01 --- /dev/null +++ b/Gems/Multiplayer/Code/Tests/ServerHierarchyBenchmarks.cpp @@ -0,0 +1,118 @@ +/* + * 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 + * + */ + +#ifdef HAVE_BENCHMARK +#include +#include + +namespace Multiplayer +{ + /* + * Hierarchy of 16 entities: Parent -> Child_2 -> .. -> Child_16 + */ + class ServerDeepHierarchyBenchmark : public HierarchyBenchmarkBase + { + public: + const NetEntityId RootNetEntityId = NetEntityId{ 1 }; + const NetEntityId ChildNetEntityId = NetEntityId{ 2 }; + const NetEntityId ChildOfChildNetEntityId = NetEntityId{ 3 }; + + void internalSetUp() override + { + HierarchyBenchmarkBase::internalSetUp(); + + m_root = AZStd::make_unique((1), "root", RootNetEntityId, EntityInfo::Role::Root); + CreateParent(*m_root); + + m_children = AZStd::make_unique>>(); + + EntityInfo* parent = m_root.get(); + for (int i = 0; i < 15; ++i) + { + m_children->push_back(AZStd::make_shared((i + 2), "child", ChildNetEntityId, EntityInfo::Role::Child)); + CreateChildForParent(*m_children->back(), *parent); + + m_children->back()->m_entity->FindComponent()->SetParent(parent->m_entity->GetId()); + parent = m_children->back().get(); + } + } + + void internalTearDown() override + { + m_children.reset(); + m_root.reset(); + + HierarchyBenchmarkBase::internalTearDown(); + } + + AZStd::unique_ptr m_root; + AZStd::unique_ptr>> m_children; + }; + + BENCHMARK_DEFINE_F(ServerDeepHierarchyBenchmark, RebuildHierarchy)(benchmark::State& state) + { + for ([[maybe_unused]] auto value : state) + { + ForceRebuildHierarchy(m_root->m_entity); + } + } + + BENCHMARK_REGISTER_F(ServerDeepHierarchyBenchmark, RebuildHierarchy) + ->Unit(benchmark::kMicrosecond) + ; + + // Should be roughly twice the time of @RebuildHierarchy benchmark + BENCHMARK_DEFINE_F(ServerDeepHierarchyBenchmark, RebuildHierarchyRemoveAndAddLastChild)(benchmark::State& state) + { + const AZ::EntityId parentOfLastChild = m_children->at(m_children->size() - 2)->m_entity->GetId(); + + for ([[maybe_unused]] auto value : state) + { + m_children->back()->m_entity->FindComponent()->SetParent(AZ::EntityId()); + m_children->back()->m_entity->FindComponent()->SetParent(parentOfLastChild); + } + } + + BENCHMARK_REGISTER_F(ServerDeepHierarchyBenchmark, RebuildHierarchyRemoveAndAddLastChild) + ->Unit(benchmark::kMicrosecond) + ; + + // Should be roughly twice the time of @RebuildHierarchy benchmark + BENCHMARK_DEFINE_F(ServerDeepHierarchyBenchmark, RebuildHierarchyRemoveAndAddMiddleChild)(benchmark::State& state) + { + const AZ::EntityId parentOfMiddleChild = m_children->at(4)->m_entity->GetId(); + + for ([[maybe_unused]] auto value : state) + { + m_children->at(5)->m_entity->FindComponent()->SetParent(AZ::EntityId()); + m_children->at(5)->m_entity->FindComponent()->SetParent(parentOfMiddleChild); + } + } + + BENCHMARK_REGISTER_F(ServerDeepHierarchyBenchmark, RebuildHierarchyRemoveAndAddMiddleChild) + ->Unit(benchmark::kMicrosecond) + ; + + // Should be roughly twice the time of @RebuildHierarchy benchmark + BENCHMARK_DEFINE_F(ServerDeepHierarchyBenchmark, RebuildHierarchyRemoveAndAddFirstChild)(benchmark::State& state) + { + const AZ::EntityId rootId = m_children->front()->m_entity->GetId(); + + for ([[maybe_unused]] auto value : state) + { + m_children->at(1)->m_entity->FindComponent()->SetParent(AZ::EntityId()); + m_children->at(1)->m_entity->FindComponent()->SetParent(rootId); + } + } + + BENCHMARK_REGISTER_F(ServerDeepHierarchyBenchmark, RebuildHierarchyRemoveAndAddFirstChild) + ->Unit(benchmark::kMicrosecond) + ; +} + +#endif diff --git a/Gems/Multiplayer/Code/multiplayer_tests_files.cmake b/Gems/Multiplayer/Code/multiplayer_tests_files.cmake index 93fb807b66..2114143b68 100644 --- a/Gems/Multiplayer/Code/multiplayer_tests_files.cmake +++ b/Gems/Multiplayer/Code/multiplayer_tests_files.cmake @@ -8,7 +8,9 @@ set(FILES Tests/ClientHierarchyTests.cpp + Tests/ServerHierarchyBenchmarks.cpp Tests/CommonHierarchySetup.h + Tests/CommonBenchmarkSetup.h Tests/IMultiplayerConnectionMock.h Tests/Main.cpp Tests/MockInterfaces.h From 91aafdcddef85d0adb128d10165d55fc622de112 Mon Sep 17 00:00:00 2001 From: puvvadar Date: Mon, 4 Oct 2021 15:17:01 -0700 Subject: [PATCH 07/27] Fix bad include in NetworkTransformTests Signed-off-by: puvvadar --- Gems/Multiplayer/Code/Tests/NetworkTransformTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Tests/NetworkTransformTests.cpp b/Gems/Multiplayer/Code/Tests/NetworkTransformTests.cpp index 94cb94e000..359c8003a4 100644 --- a/Gems/Multiplayer/Code/Tests/NetworkTransformTests.cpp +++ b/Gems/Multiplayer/Code/Tests/NetworkTransformTests.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include namespace Multiplayer { From 7f75dc6dee8f3e7e34e0605187a5386868ad56aa Mon Sep 17 00:00:00 2001 From: Dennis Brakhane Date: Tue, 5 Oct 2021 02:41:35 +0200 Subject: [PATCH 08/27] Fix "index out of range" error in AssetProcessor (#4324) * Fix "index out of range" error When the parent is the tree root element, beginInsertRows must be called with an invalid (but legal) index. A QModelIndex with a row index of zero when the parent has no children is an illegal index and will result in "undefined behavior", like the "index out of range" one. Therefore, if our parent is the tree root element, we use QModelIndex() instead. Fixes #2343 Signed-off-by: Dennis Brakhane * Use QModelIndex() instead of createIndex(-1, -1) Both do the same, but the former is Qt best practise. Signed-off-by: Dennis Brakhane * add some sanity checks in debug mode Using illegal ModelIndices can result in hard to debug problems later on, so add a few checks to help spotting them sooner. Signed-off-by: Dennis Brakhane --- Code/Editor/UndoDropDown.cpp | 4 ++-- Code/Tools/AssetProcessor/native/ui/AssetTreeModel.cpp | 8 ++++++-- .../AssetProcessor/native/ui/ProductAssetTreeModel.cpp | 9 +++++++-- .../AssetProcessor/native/ui/SourceAssetTreeModel.cpp | 10 +++++++--- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/Code/Editor/UndoDropDown.cpp b/Code/Editor/UndoDropDown.cpp index 6bf807ebf4..4f346b57dd 100644 --- a/Code/Editor/UndoDropDown.cpp +++ b/Code/Editor/UndoDropDown.cpp @@ -101,13 +101,13 @@ public: if (fresh.size() < m_stackNames.size()) { - beginRemoveRows(createIndex(-1, -1), static_cast(fresh.size()), static_cast(m_stackNames.size() - 1)); + beginRemoveRows(QModelIndex(), static_cast(fresh.size()), static_cast(m_stackNames.size() - 1)); m_stackNames = fresh; endRemoveRows(); } else { - beginInsertRows(createIndex(-1, -1), static_cast(m_stackNames.size()), static_cast(fresh.size() - 1)); + beginInsertRows(QModelIndex(), static_cast(m_stackNames.size()), static_cast(fresh.size() - 1)); m_stackNames = fresh; endInsertRows(); } diff --git a/Code/Tools/AssetProcessor/native/ui/AssetTreeModel.cpp b/Code/Tools/AssetProcessor/native/ui/AssetTreeModel.cpp index 4c2f168d4a..8d889343f9 100644 --- a/Code/Tools/AssetProcessor/native/ui/AssetTreeModel.cpp +++ b/Code/Tools/AssetProcessor/native/ui/AssetTreeModel.cpp @@ -168,7 +168,9 @@ namespace AssetProcessor if (childItem) { - return createIndex(row, column, childItem); + QModelIndex index = createIndex(row, column, childItem); + Q_ASSERT(checkIndex(index)); + return index; } return QModelIndex(); } @@ -197,7 +199,9 @@ namespace AssetProcessor { return QModelIndex(); } - return createIndex(parentItem->GetRow(), 0, parentItem); + QModelIndex parentIndex = createIndex(parentItem->GetRow(), 0, parentItem); + Q_ASSERT(checkIndex(parentIndex)); + return parentIndex; } bool AssetTreeModel::hasChildren(const QModelIndex &parent) const diff --git a/Code/Tools/AssetProcessor/native/ui/ProductAssetTreeModel.cpp b/Code/Tools/AssetProcessor/native/ui/ProductAssetTreeModel.cpp index 0574f00961..3f3a6b7a65 100644 --- a/Code/Tools/AssetProcessor/native/ui/ProductAssetTreeModel.cpp +++ b/Code/Tools/AssetProcessor/native/ui/ProductAssetTreeModel.cpp @@ -92,6 +92,7 @@ namespace AssetProcessor } QModelIndex parentIndex = createIndex(parent->GetRow(), 0, parent); + Q_ASSERT(checkIndex(parentIndex)); beginRemoveRows(parentIndex, assetToRemove->GetRow(), assetToRemove->GetRow()); @@ -179,6 +180,8 @@ namespace AssetProcessor QModelIndex existingIndexStart = createIndex(existingEntry->second->GetRow(), 0, existingEntry->second); QModelIndex existingIndexEnd = createIndex(existingEntry->second->GetRow(), existingEntry->second->GetColumnCount() - 1, existingEntry->second); + Q_ASSERT(checkIndex(existingIndexStart)); + Q_ASSERT(checkIndex(existingIndexEnd)); dataChanged(existingIndexStart, existingIndexEnd); return; } @@ -205,7 +208,8 @@ namespace AssetProcessor { if (!modelIsResetting) { - QModelIndex parentIndex = createIndex(parentItem->GetRow(), 0, parentItem); + QModelIndex parentIndex = parentItem == m_root.get() ? QModelIndex() : createIndex(parentItem->GetRow(), 0, parentItem); + Q_ASSERT(checkIndex(parentIndex)); beginInsertRows(parentIndex, parentItem->getChildCount(), parentItem->getChildCount()); } nextParent = parentItem->CreateChild(ProductAssetTreeItemData::MakeShared(nullptr, currentFullFolderPath.Native(), currentPath.c_str(), true, AZ::Uuid::CreateNull())); @@ -231,7 +235,8 @@ namespace AssetProcessor if (!modelIsResetting) { - QModelIndex parentIndex = createIndex(parentItem->GetRow(), 0, parentItem); + QModelIndex parentIndex = parentItem == m_root.get() ? QModelIndex() : createIndex(parentItem->GetRow(), 0, parentItem); + Q_ASSERT(checkIndex(parentIndex)); beginInsertRows(parentIndex, parentItem->getChildCount(), parentItem->getChildCount()); } diff --git a/Code/Tools/AssetProcessor/native/ui/SourceAssetTreeModel.cpp b/Code/Tools/AssetProcessor/native/ui/SourceAssetTreeModel.cpp index 88fbe5a204..eaebc57ca4 100644 --- a/Code/Tools/AssetProcessor/native/ui/SourceAssetTreeModel.cpp +++ b/Code/Tools/AssetProcessor/native/ui/SourceAssetTreeModel.cpp @@ -13,6 +13,7 @@ #include #include #include +#include namespace AssetProcessor { @@ -102,7 +103,8 @@ namespace AssetProcessor { if (!modelIsResetting) { - QModelIndex parentIndex = createIndex(parentItem->GetRow(), 0, parentItem); + QModelIndex parentIndex = parentItem == m_root.get() ? QModelIndex() : createIndex(parentItem->GetRow(), 0, parentItem); + Q_ASSERT(checkIndex(parentIndex)); beginInsertRows(parentIndex, parentItem->getChildCount(), parentItem->getChildCount()); } nextParent = parentItem->CreateChild(SourceAssetTreeItemData::MakeShared(nullptr, nullptr, currentFullFolderPath.Native(), currentPath.c_str(), true)); @@ -118,7 +120,8 @@ namespace AssetProcessor if (!modelIsResetting) { - QModelIndex parentIndex = createIndex(parentItem->GetRow(), 0, parentItem); + QModelIndex parentIndex = parentItem == m_root.get() ? QModelIndex() : createIndex(parentItem->GetRow(), 0, parentItem); + Q_ASSERT(checkIndex(parentIndex)); beginInsertRows(parentIndex, parentItem->getChildCount(), parentItem->getChildCount()); } @@ -173,7 +176,8 @@ namespace AssetProcessor return; } - QModelIndex parentIndex = createIndex(parent->GetRow(), 0, parent); + QModelIndex parentIndex = parent == m_root.get() ? QModelIndex() : createIndex(parent->GetRow(), 0, parent); + Q_ASSERT(checkIndex(parentIndex)); beginRemoveRows(parentIndex, assetToRemove->GetRow(), assetToRemove->GetRow()); From 31b2fe427bccf509a20f2aeaa8b8160f1b95a4e5 Mon Sep 17 00:00:00 2001 From: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> Date: Mon, 4 Oct 2021 21:10:39 -0400 Subject: [PATCH 09/27] Added a helpful comment on hierarchy benchmark Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> --- Gems/Multiplayer/Code/Tests/ServerHierarchyBenchmarks.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Gems/Multiplayer/Code/Tests/ServerHierarchyBenchmarks.cpp b/Gems/Multiplayer/Code/Tests/ServerHierarchyBenchmarks.cpp index 6a404bfa01..f6f82ebe2b 100644 --- a/Gems/Multiplayer/Code/Tests/ServerHierarchyBenchmarks.cpp +++ b/Gems/Multiplayer/Code/Tests/ServerHierarchyBenchmarks.cpp @@ -14,6 +14,7 @@ namespace Multiplayer { /* * Hierarchy of 16 entities: Parent -> Child_2 -> .. -> Child_16 + * By default the maximum size of a hierarchy is defined by bg_hierarchyEntityMaxLimit (16). */ class ServerDeepHierarchyBenchmark : public HierarchyBenchmarkBase { From ca26599f93e27ee41cb014e6df26852f4f78e921 Mon Sep 17 00:00:00 2001 From: hultonha <82228511+hultonha@users.noreply.github.com> Date: Tue, 5 Oct 2021 09:58:43 +0100 Subject: [PATCH 10/27] Remove legacy sandbox picking - no longer used (#4472) Signed-off-by: hultonha --- .../SandboxIntegration.cpp | 59 +------------------ .../SandboxIntegration.h | 8 --- Code/Editor/Viewport.h | 2 +- .../API/ToolsApplicationAPI.h | 6 -- 4 files changed, 2 insertions(+), 73 deletions(-) diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp index 666700a874..b9e4878879 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp @@ -142,8 +142,7 @@ void GetSelectedEntitiesSetWithFlattenedHierarchy(AzToolsFramework::EntityIdSet& } SandboxIntegrationManager::SandboxIntegrationManager() - : m_inObjectPickMode(false) - , m_startedUndoRecordingNestingLevel(0) + : m_startedUndoRecordingNestingLevel(0) , m_dc(nullptr) , m_notificationWindowManager(new AzToolsFramework::SliceOverridesNotificationWindowManager()) { @@ -1000,62 +999,6 @@ void SandboxIntegrationManager::SetupSliceContextMenu_Modify(QMenu* menu, const revertAction->setEnabled(canRevert); } -void SandboxIntegrationManager::HandleObjectModeSelection(const AZ::Vector2& point, [[maybe_unused]] int flags, bool& handled) -{ - // Todo - Use a custom "edit tool". This will eliminate the need for this bus message entirely, which technically - // makes this feature less intrusive on Sandbox. - // UPDATE: This is now provided by EditorPickEntitySelection when the new Viewport Interaction Model changes are enabled. - if (m_inObjectPickMode) - { - CViewport* view = GetIEditor()->GetViewManager()->GetGameViewport(); - const QPoint viewPoint(static_cast(point.GetX()), static_cast(point.GetY())); - - HitContext hitInfo; - hitInfo.view = view; - if (view->HitTest(viewPoint, hitInfo)) - { - if (hitInfo.object && (hitInfo.object->GetType() == OBJTYPE_AZENTITY)) - { - CComponentEntityObject* entityObject = static_cast(hitInfo.object); - AzToolsFramework::EditorPickModeRequestBus::Broadcast( - &AzToolsFramework::EditorPickModeRequests::PickModeSelectEntity, entityObject->GetAssociatedEntityId()); - } - } - - AzToolsFramework::EditorPickModeRequestBus::Broadcast( - &AzToolsFramework::EditorPickModeRequests::StopEntityPickMode); - - handled = true; - } -} - -void SandboxIntegrationManager::UpdateObjectModeCursor(AZ::u32& cursorId, AZStd::string& cursorStr) -{ - if (m_inObjectPickMode) - { - cursorId = static_cast(STD_CURSOR_HAND); - cursorStr = "Pick an entity..."; - } -} - -void SandboxIntegrationManager::OnEntityPickModeStarted() -{ - m_inObjectPickMode = true; - - // Currently this object pick mode is activated only via PropertyEntityIdCtrl picker. - // When the picker button is clicked, we transfer focus to the viewport so the - // spacebar can still be used to activate selection helpers. - if (CViewport* view = GetIEditor()->GetViewManager()->GetGameViewport()) - { - view->SetFocus(); - } -} - -void SandboxIntegrationManager::OnEntityPickModeStopped() -{ - m_inObjectPickMode = false; -} - void SandboxIntegrationManager::CreateEditorRepresentation(AZ::Entity* entity) { IEditor* editor = GetIEditor(); diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h index 617c5cb2c8..40962409a3 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h @@ -93,7 +93,6 @@ namespace AzToolsFramework class SandboxIntegrationManager : private AzToolsFramework::ToolsApplicationEvents::Bus::Handler , private AzToolsFramework::EditorRequests::Bus::Handler - , private AzToolsFramework::EditorPickModeNotificationBus::Handler , private AzToolsFramework::EditorContextMenuBus::Handler , private AzToolsFramework::EditorWindowRequests::Bus::Handler , private AzFramework::AssetCatalogEventBus::Handler @@ -140,8 +139,6 @@ private: QDockWidget* InstanceViewPane(const char* paneName) override; void CloseViewPane(const char* paneName) override; void BrowseForAssets(AzToolsFramework::AssetBrowser::AssetSelectionModel& selection) override; - void HandleObjectModeSelection(const AZ::Vector2& point, int flags, bool& handled) override; - void UpdateObjectModeCursor(AZ::u32& cursorId, AZStd::string& cursorStr) override; void CreateEditorRepresentation(AZ::Entity* entity) override; bool DestroyEditorRepresentation(AZ::EntityId entityId, bool deleteAZEntity) override; void CloneSelection(bool& handled) override; @@ -175,10 +172,6 @@ private: QWidget* GetAppMainWindow() override; ////////////////////////////////////////////////////////////////////////// - // EditorPickModeNotificationBus - void OnEntityPickModeStarted() override; - void OnEntityPickModeStopped() override; - ////////////////////////////////////////////////////////////////////////// // AzToolsFramework::EditorContextMenu::Bus::Handler overrides void PopulateEditorGlobalContextMenu(QMenu* menu, const AZ::Vector2& point, int flags) override; @@ -281,7 +274,6 @@ private: private: AZ::Vector2 m_contextMenuViewPoint; - int m_inObjectPickMode; short m_startedUndoRecordingNestingLevel; // used in OnBegin/EndUndo to ensure we only accept undo's we started recording AzToolsFramework::SliceOverridesNotificationWindowManager* m_notificationWindowManager; diff --git a/Code/Editor/Viewport.h b/Code/Editor/Viewport.h index fdb8332479..7f8ccc4c4f 100644 --- a/Code/Editor/Viewport.h +++ b/Code/Editor/Viewport.h @@ -157,7 +157,7 @@ public: virtual Vec3 SnapToGrid(const Vec3& vec) = 0; - //! Get selection procision tolerance. + //! Get selection precision tolerance. virtual float GetSelectionTolerance() const = 0; ////////////////////////////////////////////////////////////////////////// diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h index c037747a08..9e29b9813c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h @@ -764,12 +764,6 @@ namespace AzToolsFramework //! Spawn asset browser for the appropriate asset types. virtual void BrowseForAssets(AssetBrowser::AssetSelectionModel& /*selection*/) = 0; - /// Allow interception of selection / left-mouse clicks in ObjectMode, for customizing selection behavior. - virtual void HandleObjectModeSelection(const AZ::Vector2& /*point*/, int /*flags*/, bool& /*handled*/) {} - - /// Allow interception of cursor, for customizing selection behavior. - virtual void UpdateObjectModeCursor(AZ::u32& /*cursorId*/, AZStd::string& /*cursorStr*/) {} - /// Creates editor-side representation of an underlying entity. virtual void CreateEditorRepresentation(AZ::Entity* /*entity*/) { } From 5cf6236bd9912b03bfe4c6fd04c52dafb55504ba Mon Sep 17 00:00:00 2001 From: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> Date: Tue, 5 Oct 2021 08:46:48 -0400 Subject: [PATCH 11/27] Fixing development build break Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> --- Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h b/Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h index e0018e2f26..dd32e743e2 100644 --- a/Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h +++ b/Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h @@ -19,7 +19,7 @@ #include #include #include -#include +#include namespace Multiplayer { From c2a84de38c1531c9fa618de3822c603b92d2e813 Mon Sep 17 00:00:00 2001 From: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> Date: Tue, 5 Oct 2021 08:53:50 -0400 Subject: [PATCH 12/27] Updated mock-like interfaces for benchmarks Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> --- .../Code/Tests/CommonBenchmarkSetup.h | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h b/Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h index dd32e743e2..7f98d22702 100644 --- a/Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h +++ b/Gems/Multiplayer/Code/Tests/CommonBenchmarkSetup.h @@ -100,6 +100,11 @@ namespace Multiplayer { return {}; } + + AZ::TimeUs GetElapsedTimeUs() const override + { + return {}; + } }; class BenchmarkNetworkTime : public Multiplayer::INetworkTime @@ -215,7 +220,7 @@ namespace Multiplayer NetworkEntityTracker* GetNetworkEntityTracker() override { return &m_tracker; } NetworkEntityAuthorityTracker* GetNetworkEntityAuthorityTracker() override { return &m_authorityTracker; } MultiplayerComponentRegistry* GetMultiplayerComponentRegistry() override { return &m_multiplayerComponentRegistry; } - HostId GetHostId() const override { return {}; } + const HostId& GetHostId() const override { return m_hostId; } EntityList CreateEntitiesImmediate( [[maybe_unused]] const PrefabEntityId& prefabEntryId, [[maybe_unused]] NetEntityRole netEntityRole, @@ -271,7 +276,7 @@ namespace Multiplayer NetworkEntityHandle AddEntityToEntityMap(NetEntityId netEntityId, AZ::Entity* entity) override { m_networkEntityMap[netEntityId] = entity; - return NetworkEntityHandle(entity, netEntityId, &m_tracker); + return NetworkEntityHandle(entity, &m_tracker); } ConstNetworkEntityHandle GetEntity(NetEntityId netEntityId) const override @@ -300,9 +305,15 @@ namespace Multiplayer return {}; } + void Initialize([[maybe_unused]] const HostId& hostId, [[maybe_unused]] AZStd::unique_ptr entityDomain) override {} + bool IsInitialized() const override { return true; } + IEntityDomain* GetEntityDomain() const override { return nullptr; } + void DebugDraw() const override {} + NetworkEntityTracker m_tracker; NetworkEntityAuthorityTracker m_authorityTracker; MultiplayerComponentRegistry m_multiplayerComponentRegistry; + HostId m_hostId; }; class BenchmarkMultiplayer : public Multiplayer::IMultiplayer @@ -313,7 +324,7 @@ namespace Multiplayer MultiplayerAgentType GetAgentType() const override { return {}; } void InitializeMultiplayer([[maybe_unused]] MultiplayerAgentType state) override {} bool StartHosting([[maybe_unused]] uint16_t port, [[maybe_unused]] bool isDedicated) override { return {}; } - bool Connect([[maybe_unused]] AZStd::string remoteAddress, [[maybe_unused]] uint16_t port) override { return {}; } + bool Connect([[maybe_unused]] const AZStd::string& remoteAddress, [[maybe_unused]] uint16_t port) override { return {}; } void Terminate([[maybe_unused]] AzNetworking::DisconnectReason reason) override {} void AddClientDisconnectedHandler([[maybe_unused]] ClientDisconnectedEvent::Handler& handler) override {} void AddConnectionAcquiredHandler([[maybe_unused]] ConnectionAcquiredEvent::Handler& handler) override {} @@ -326,6 +337,14 @@ namespace Multiplayer INetworkEntityManager* GetNetworkEntityManager() override { return &m_manager; } void SetFilterEntityManager([[maybe_unused]] IFilterEntityManager* entityFilter) override {} IFilterEntityManager* GetFilterEntityManager() override { return {}; } + void AddClientMigrationStartEventHandler([[maybe_unused]] ClientMigrationStartEvent::Handler& handler) override {} + void AddClientMigrationEndEventHandler([[maybe_unused]] ClientMigrationEndEvent::Handler& handler) override {} + void AddNotifyClientMigrationHandler([[maybe_unused]] NotifyClientMigrationEvent::Handler& handler) override {} + void AddNotifyEntityMigrationEventHandler([[maybe_unused]] NotifyEntityMigrationEvent::Handler& handler) override {} + void SendNotifyClientMigrationEvent([[maybe_unused]] const HostId& hostId, [[maybe_unused]] uint64_t userIdentifier, [[maybe_unused]] ClientInputId lastClientInputId) override {} + void SendNotifyEntityMigrationEvent([[maybe_unused]] const ConstNetworkEntityHandle& entityHandle, [[maybe_unused]] const HostId& remoteHostId) override {} + void SetShouldSpawnNetworkEntities([[maybe_unused]] bool value) override {} + bool GetShouldSpawnNetworkEntities() const override { return true; } BenchmarkNetworkEntityManager& m_manager; }; From 365dd617787c098afd67406b89bffab259bd798f Mon Sep 17 00:00:00 2001 From: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> Date: Tue, 5 Oct 2021 11:22:36 -0500 Subject: [PATCH 13/27] [LY-111998] Surface Tags didn't refresh immediately. (#4468) When adding or modifying surface tags to a surface tag list asset, the surface tag lists didn't immediately refresh in the Editor. There were a couple of bugs in the way the tag assets were getting loaded and monitored that are now fixed. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> --- .../EditorSurfaceDataSystemComponent.cpp | 54 +++++++++---------- .../Editor/EditorSurfaceDataSystemComponent.h | 2 +- 2 files changed, 26 insertions(+), 30 deletions(-) diff --git a/Gems/SurfaceData/Code/Source/Editor/EditorSurfaceDataSystemComponent.cpp b/Gems/SurfaceData/Code/Source/Editor/EditorSurfaceDataSystemComponent.cpp index e9f7861125..a5bf51d0fe 100644 --- a/Gems/SurfaceData/Code/Source/Editor/EditorSurfaceDataSystemComponent.cpp +++ b/Gems/SurfaceData/Code/Source/Editor/EditorSurfaceDataSystemComponent.cpp @@ -163,65 +163,61 @@ namespace SurfaceData // AssetManager::FindOrCreateAsset, it's possible for those locks to get locked in reverse on a loading thread, causing a deadlock. for (auto& assetId : surfaceTagAssetIds) { - m_surfaceTagNameAssets[assetId] = AZ::Data::AssetManager::Instance().GetAsset( - assetId, azrtti_typeid(), AZ::Data::AssetLoadBehavior::Default); - - // If any assets are still loading (which they likely will be), listen for the OnAssetReady event and refresh the Editor - // UI as each one finishes loading. - if (!m_surfaceTagNameAssets[assetId].IsReady()) - { - AZ::Data::AssetBus::MultiHandler::BusConnect(assetId); - } + LoadAsset(assetId); } } + void EditorSurfaceDataSystemComponent::LoadAsset(const AZ::Data::AssetId& assetId) + { + m_surfaceTagNameAssets[assetId] = AZ::Data::AssetManager::Instance().GetAsset( + assetId, azrtti_typeid(), AZ::Data::AssetLoadBehavior::Default); + + // Connect to the bus for this asset so we can monitor for both OnAssetReady and OnAssetReloaded events + AZ::Data::AssetBus::MultiHandler::BusConnect(assetId); + } + void EditorSurfaceDataSystemComponent::OnCatalogAssetAdded(const AZ::Data::AssetId& assetId) { AZ::Data::AssetInfo assetInfo; AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetInfo, &AZ::Data::AssetCatalogRequests::GetAssetInfoById, assetId); - const auto assetType = azrtti_typeid(); - if (assetInfo.m_assetType == assetType) + if (assetInfo.m_assetType == azrtti_typeid()) { - AZ::Data::AssetBus::MultiHandler::BusConnect(assetId); + // A new Surface Tag asset was added, so load it. + LoadAsset(assetId); } } - void EditorSurfaceDataSystemComponent::OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) + void EditorSurfaceDataSystemComponent::OnCatalogAssetRemoved(const AZ::Data::AssetId& assetId, const AZ::Data::AssetInfo& assetInfo) { - AZ::Data::AssetInfo assetInfo; - AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetInfo, &AZ::Data::AssetCatalogRequests::GetAssetInfoById, assetId); - - const auto assetType = azrtti_typeid(); - if (assetInfo.m_assetType == assetType) + if (assetInfo.m_assetType == azrtti_typeid()) { - AZ::Data::AssetBus::MultiHandler::BusConnect(assetId); + // A Surface Tag asset was removed, so stop listening for it and remove it from our set of loaded assets. + // Note: This case should never really happen in practice - we're keeping the asset loaded, so the file will remain + // locked while the Editor is running and shouldn't be able to be deleted. + AZ::Data::AssetBus::MultiHandler::BusDisconnect(assetId); + m_surfaceTagNameAssets.erase(assetId); } } - void EditorSurfaceDataSystemComponent::OnCatalogAssetRemoved(const AZ::Data::AssetId& assetId, const AZ::Data::AssetInfo& /*assetInfo*/) - { - m_surfaceTagNameAssets.erase(assetId); - } - void EditorSurfaceDataSystemComponent::OnAssetReloaded(AZ::Data::Asset asset) { - OnAssetReady(asset); + AddAsset(asset); } void EditorSurfaceDataSystemComponent::OnAssetReady(AZ::Data::Asset asset) { - AZ::Data::AssetBus::MultiHandler::BusDisconnect(asset.GetId()); AddAsset(asset); } void EditorSurfaceDataSystemComponent::AddAsset(AZ::Data::Asset& asset) { - const auto assetType = azrtti_typeid(); - if (asset.GetType() == assetType) + if (asset.GetType() == azrtti_typeid()) { m_surfaceTagNameAssets[asset.GetId()] = asset; - AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(&AzToolsFramework::PropertyEditorGUIMessages::RequestRefresh, AzToolsFramework::PropertyModificationRefreshLevel::Refresh_AttributesAndValues); + AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast( + &AzToolsFramework::PropertyEditorGUIMessages::RequestRefresh, + AzToolsFramework::PropertyModificationRefreshLevel::Refresh_AttributesAndValues); } } } diff --git a/Gems/SurfaceData/Code/Source/Editor/EditorSurfaceDataSystemComponent.h b/Gems/SurfaceData/Code/Source/Editor/EditorSurfaceDataSystemComponent.h index f35cab56f4..603cffc56d 100644 --- a/Gems/SurfaceData/Code/Source/Editor/EditorSurfaceDataSystemComponent.h +++ b/Gems/SurfaceData/Code/Source/Editor/EditorSurfaceDataSystemComponent.h @@ -48,6 +48,7 @@ namespace SurfaceData private: + void LoadAsset(const AZ::Data::AssetId& assetId); void AddAsset(AZ::Data::Asset& asset); //////////////////////////////////////////////////////////////////////// @@ -63,7 +64,6 @@ namespace SurfaceData //////////////////////////////////////////////////////////////////////// // AzFramework::AssetCatalogEventBus void OnCatalogLoaded(const char* /*catalogFile*/) override; - void OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) override; void OnCatalogAssetAdded(const AZ::Data::AssetId& assetId) override; void OnCatalogAssetRemoved(const AZ::Data::AssetId& assetId, const AZ::Data::AssetInfo& assetInfo) override; From 14474dbac72650c05eeea0927f6fdc5d2b98fe11 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Tue, 5 Oct 2021 11:24:37 -0500 Subject: [PATCH 14/27] Swapped the order in which the engine.pak is searched (#4455) * Swapped the order in which the engine.pak is searched First the Project Cache Root folder is searched before falling back to the Executable Directory Removed the need for the engine.json and project.json in a project release layout when a "Cache" directory exist at the root. The project root uses the the first "Cache" directory it finds by scanning upwards as if fails to find a project.json, The engine root use the project root, if it fails to reconcile the engine path using project.json "engine" key and the o3de_manifest.json "engines_path" object. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed Generation of the engine.json and project.json in Release Install builds. The project and engine path can be determined based on the Cache directory location. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Added missing space for enginePakOpened Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Adding missing endif() and bracket argument terminator. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- .../Settings/SettingsRegistryMergeUtils.cpp | 12 ++++++-- .../Application/GameApplication.cpp | 28 ++++++++++--------- cmake/Platform/Common/Install_common.cmake | 15 ---------- cmake/Projects.cmake | 5 +--- 4 files changed, 26 insertions(+), 34 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp index 113fdd433e..e1bd717e7b 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp @@ -276,7 +276,9 @@ namespace AZ::SettingsRegistryMergeUtils return engineRoot; } - return {}; + // Fall back to using the project root as the engine root if the engine path could not be reconciled + // by checking the project.json "engine" string within o3de_manifest.json "engine_paths" object + return projectRoot; } AZ::IO::FixedMaxPath FindProjectRoot(SettingsRegistryInterface& settingsRegistry) @@ -309,7 +311,13 @@ namespace AZ::SettingsRegistryMergeUtils return projectRoot; } - return {}; + // Step 3 Check for a "Cache" directory by scanning upwards from the executable directory + if (auto candidateRoot = Internal::ScanUpRootLocator("Cache"); + !candidateRoot.empty() && AZ::IO::SystemFile::IsDirectory(candidateRoot.c_str())) + { + projectRoot = AZStd::move(candidateRoot); + } + return projectRoot; } AZStd::string_view ConfigParserSettings::DefaultCommentPrefixFilter(AZStd::string_view line) diff --git a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp index 475a7d5504..424132b624 100644 --- a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp +++ b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp @@ -28,20 +28,22 @@ namespace AzGameFramework // can read from the FileIOBase instance if available m_settingsRegistry->SetUseFileIO(true); - // Attempt to mount the engine pak from the Executable Directory - // at the Assets alias, otherwise to attempting to mount the engine pak - // from the Cache folder - AZ::IO::FixedMaxPath enginePakPath = AZ::Utils::GetExecutableDirectory(); - enginePakPath /= "engine.pak"; - if (!m_archive->OpenPack("@assets@", enginePakPath.Native())) + // Attempt to mount the engine pak to the project product asset alias + // Search Order: + // - Project Cache Root Directory + // - Executable Directory + bool enginePakOpened{}; + AZ::IO::FixedMaxPath enginePakPath; + if (m_settingsRegistry->Get(enginePakPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder)) { - enginePakPath.clear(); - if (m_settingsRegistry->Get(enginePakPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder)) - { - // fall back to checking Project Cache Root. - enginePakPath /= "engine.pak"; - m_archive->OpenPack("@assets@", enginePakPath.Native()); - } + // fall back to checking Project Cache Root. + enginePakPath /= "engine.pak"; + enginePakOpened = m_archive->OpenPack("@projectproductassets@", enginePakPath.Native()); + } + if (!enginePakOpened) + { + enginePakPath = AZ::IO::FixedMaxPath(AZ::Utils::GetExecutableDirectory()) / "engine.pak"; + m_archive->OpenPack("@projectproductassets@", enginePakPath.Native()); } } diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 5fa7f21939..8fb2effe29 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -430,21 +430,6 @@ function(ly_setup_cmake_install) DESTINATION . COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) - string(CONFIGURE [=[ -if("${CMAKE_INSTALL_CONFIG_NAME}" MATCHES "^([Rr][Ee][Ll][Ee][Aa][Ss][Ee])$") - set(install_output_folder "${CMAKE_INSTALL_PREFIX}/@runtime_output_directory@") - file(WRITE ${install_output_folder}/engine.json -"{ - \"engine_name\": \"@LY_VERSION_ENGINE_NAME@\" -}") -endif() -]=] - install_engine_json_release - @ONLY - ) - install(CODE ${install_engine_json_release} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} # use the default for the time being - ) # Collect all Find files that were added with ly_add_external_target_path unset(additional_find_files) diff --git a/cmake/Projects.cmake b/cmake/Projects.cmake index 6109229e72..c09fe0fc6f 100644 --- a/cmake/Projects.cmake +++ b/cmake/Projects.cmake @@ -173,12 +173,9 @@ if("${CMAKE_INSTALL_CONFIG_NAME}" MATCHES "^([Rr][Ee][Ll][Ee][Aa][Ss][Ee])$") message(STATUS "${install_output_folder}/engine.pak generated") endif() endif() - file(WRITE ${install_output_folder}/project.json -"{ - \"project_name\": \"@project_name@\" -}") endif() ]=]) + string(CONFIGURE "${install_engine_pak_template}" install_engine_pak_code @ONLY) ly_install_run_code("${install_engine_pak_code}") From 36eac35bc35926fca3edfb75753b845d0a592eac Mon Sep 17 00:00:00 2001 From: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> Date: Tue, 5 Oct 2021 11:38:38 -0500 Subject: [PATCH 15/27] Removing xfail from optimized Gradient Signal tests and disabling non-optimized suite (#4475) Signed-off-by: jckand-amzn --- .../Gem/PythonTests/largeworlds/CMakeLists.txt | 13 ------------- .../gradient_signal/TestSuite_Periodic_Optimized.py | 1 - 2 files changed, 14 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt index f1299ddc2d..d5c7fd5109 100644 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt @@ -96,19 +96,6 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_ ## GradientSignal ## - ly_add_pytest( - NAME AutomatedTesting::GradientSignalTests_Periodic - TEST_SERIAL - TEST_SUITE periodic - PATH ${CMAKE_CURRENT_LIST_DIR}/gradient_signal/TestSuite_Periodic.py - RUNTIME_DEPENDENCIES - AZ::AssetProcessor - Legacy::Editor - AutomatedTesting.Assets - COMPONENT - LargeWorlds - ) - ly_add_pytest( NAME AutomatedTesting::GradientSignalTests_Periodic_Optimized TEST_SERIAL diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/TestSuite_Periodic_Optimized.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/TestSuite_Periodic_Optimized.py index f996a1f8c3..514504d324 100644 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/TestSuite_Periodic_Optimized.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/TestSuite_Periodic_Optimized.py @@ -10,7 +10,6 @@ import pytest from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite -@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.") @pytest.mark.SUITE_periodic @pytest.mark.parametrize("launcher_platform", ['windows_editor']) @pytest.mark.parametrize("project", ["AutomatedTesting"]) From 4a4c93f8662e0cc69c178ebd23101bf27762e86d Mon Sep 17 00:00:00 2001 From: sphrose <82213493+sphrose@users.noreply.github.com> Date: Tue, 5 Oct 2021 17:53:05 +0100 Subject: [PATCH 16/27] Terrain/sphrose/surface gradient list component (#4409) * cherry-pick conflict fix Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> * Missed include file Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> * review changes. Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> * cherry-pick merge fix Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> * review changes. Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> * bug fix Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> * review changes. Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> * compile fix Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> * compile fix Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> --- .../Terrain/TerrainDataRequestBus.h | 47 +++++- Gems/PhysX/Code/Tests/PhysXTestUtil.h | 4 + .../SurfaceData/SurfaceDataConstants.h | 3 +- .../Ebuses/TerrainAreaSurfaceRequestBus.h | 35 ++++ .../Ebuses/TerrainGradientSurfaceListBus.h | 34 ++++ .../TerrainSurfaceGradientListComponent.cpp | 157 ++++++++++++++++++ .../TerrainSurfaceGradientListComponent.h | 77 +++++++++ ...torTerrainSurfaceGradientListComponent.cpp | 22 +++ ...ditorTerrainSurfaceGradientListComponent.h | 32 ++++ .../Code/Source/EditorTerrainModule.cpp | 2 + Gems/Terrain/Code/Source/TerrainModule.cpp | 2 + .../Source/TerrainSystem/TerrainSystem.cpp | 143 +++++++++++++--- .../Code/Source/TerrainSystem/TerrainSystem.h | 30 +++- .../Code/terrain_editor_shared_files.cmake | 2 + Gems/Terrain/Code/terrain_files.cmake | 3 + 15 files changed, 567 insertions(+), 26 deletions(-) create mode 100644 Gems/Terrain/Code/Include/Terrain/Ebuses/TerrainAreaSurfaceRequestBus.h create mode 100644 Gems/Terrain/Code/Include/Terrain/Ebuses/TerrainGradientSurfaceListBus.h create mode 100644 Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.cpp create mode 100644 Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.h create mode 100644 Gems/Terrain/Code/Source/EditorComponents/EditorTerrainSurfaceGradientListComponent.cpp create mode 100644 Gems/Terrain/Code/Source/EditorComponents/EditorTerrainSurfaceGradientListComponent.h diff --git a/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h b/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h index 92eb28a110..3f6a8f0960 100644 --- a/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h +++ b/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h @@ -8,6 +8,7 @@ #pragma once #include +#include #include #include #include @@ -17,16 +18,38 @@ namespace AzFramework { namespace SurfaceData { + namespace Constants + { + static const char* s_unassignedTagName = "(unassigned)"; + } + struct SurfaceTagWeight { AZ_TYPE_INFO(SurfaceTagWeight, "{EA14018E-E853-4BF5-8E13-D83BB99A54CC}"); - AZ::Crc32 m_surfaceType; - float m_weight; //! A Value in the range [0.0f .. 1.0f] + AZ::Crc32 m_surfaceType = AZ::Crc32(Constants::s_unassignedTagName); + float m_weight = 0.0f; //! A Value in the range [0.0f .. 1.0f] //! Don't call this directly. TerrainDataRequests::Reflect is doing it already. static void Reflect(AZ::ReflectContext* context); }; + + struct SurfaceTagWeightComparator + { + bool operator()(const SurfaceTagWeight& tagWeight1, const SurfaceTagWeight& tagWeight2) const + { + if (!AZ::IsClose(tagWeight1.m_weight, tagWeight2.m_weight)) + { + return tagWeight1.m_weight > tagWeight2.m_weight; + } + else + { + return tagWeight1.m_surfaceType > tagWeight2.m_surfaceType; + } + } + }; + + using OrderedSurfaceTagWeightSet = AZStd::set; } //namespace SurfaceData namespace Terrain @@ -75,8 +98,28 @@ namespace AzFramework //! @terrainExists: Can be nullptr. If != nullptr then, if there's no terrain at location x,y or location x,y is inside a terrain HOLE then *terrainExistsPtr will be set to false, //! otherwise *terrainExistsPtr will be set to true. virtual SurfaceData::SurfaceTagWeight GetMaxSurfaceWeight(AZ::Vector3 position, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const = 0; + virtual SurfaceData::SurfaceTagWeight GetMaxSurfaceWeightFromVector2(const AZ::Vector2& inPosition, Sampler sampleFilter = Sampler::DEFAULT, bool* terrainExistsPtr = nullptr) const = 0; virtual SurfaceData::SurfaceTagWeight GetMaxSurfaceWeightFromFloats(float x, float y, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const = 0; + //! Given an XY coordinate, return the set of surface types and weights. The Vector3 input position version is defined to ignore + //! the input Z value. + virtual void GetSurfaceWeights( + const AZ::Vector3& inPosition, + SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights, + Sampler sampleFilter = Sampler::DEFAULT, + bool* terrainExistsPtr = nullptr) const = 0; + virtual void GetSurfaceWeightsFromVector2( + const AZ::Vector2& inPosition, + SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights, + Sampler sampleFilter = Sampler::DEFAULT, + bool* terrainExistsPtr = nullptr) const = 0; + virtual void GetSurfaceWeightsFromFloats( + float x, + float y, + SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights, + Sampler sampleFilter = Sampler::DEFAULT, + bool* terrainExistsPtr = nullptr) const = 0; + //! Convenience function for low level systems that can't do a reverse lookup from Crc to string. Everyone else should use GetMaxSurfaceWeight or GetMaxSurfaceWeightFromFloats. //! Not available in the behavior context. //! Returns nullptr if the position is inside a hole or outside of the terrain boundaries. diff --git a/Gems/PhysX/Code/Tests/PhysXTestUtil.h b/Gems/PhysX/Code/Tests/PhysXTestUtil.h index 8e81b9cb89..1c86768de7 100644 --- a/Gems/PhysX/Code/Tests/PhysXTestUtil.h +++ b/Gems/PhysX/Code/Tests/PhysXTestUtil.h @@ -115,7 +115,11 @@ namespace PhysX } float GetHeightFromFloats(float, float, Sampler, bool*) const override { return {}; } AzFramework::SurfaceData::SurfaceTagWeight GetMaxSurfaceWeight(AZ::Vector3, Sampler, bool*) const override { return {}; } + AzFramework::SurfaceData::SurfaceTagWeight GetMaxSurfaceWeightFromVector2(const AZ::Vector2&, Sampler, bool*) const override { return {}; } AzFramework::SurfaceData::SurfaceTagWeight GetMaxSurfaceWeightFromFloats(float, float, Sampler, bool*) const override { return {}; } + void GetSurfaceWeights(const AZ::Vector3&, AzFramework::SurfaceData::OrderedSurfaceTagWeightSet&, Sampler, bool*) const override {} + void GetSurfaceWeightsFromVector2(const AZ::Vector2&, AzFramework::SurfaceData::OrderedSurfaceTagWeightSet&, Sampler, bool*) const override{}; + void GetSurfaceWeightsFromFloats(float, float, AzFramework::SurfaceData::OrderedSurfaceTagWeightSet&, Sampler, bool*) const override {} const char* GetMaxSurfaceName(AZ::Vector3, Sampler, bool*) const override { return {}; } bool GetIsHoleFromFloats(float, float, Sampler) const override { return {}; } AZ::Vector3 GetNormal(AZ::Vector3, Sampler, bool*) const override { return {}; } diff --git a/Gems/SurfaceData/Code/Include/SurfaceData/SurfaceDataConstants.h b/Gems/SurfaceData/Code/Include/SurfaceData/SurfaceDataConstants.h index 9b18e4f9e7..3f4a1bb605 100644 --- a/Gems/SurfaceData/Code/Include/SurfaceData/SurfaceDataConstants.h +++ b/Gems/SurfaceData/Code/Include/SurfaceData/SurfaceDataConstants.h @@ -9,12 +9,13 @@ #pragma once #include +#include namespace SurfaceData { namespace Constants { - static const char* s_unassignedTagName = "(unassigned)"; + static const char* s_unassignedTagName = AzFramework::SurfaceData::Constants::s_unassignedTagName; static const char* s_terrainHoleTagName = "terrainHole"; static const char* s_terrainTagName = "terrain"; diff --git a/Gems/Terrain/Code/Include/Terrain/Ebuses/TerrainAreaSurfaceRequestBus.h b/Gems/Terrain/Code/Include/Terrain/Ebuses/TerrainAreaSurfaceRequestBus.h new file mode 100644 index 0000000000..4c04cf1e42 --- /dev/null +++ b/Gems/Terrain/Code/Include/Terrain/Ebuses/TerrainAreaSurfaceRequestBus.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include + +#include + +namespace Terrain +{ + + //! This bus provides retrieval of information from Terrain Surfaces. + class TerrainAreaSurfaceRequests + : public AZ::ComponentBus + { + public: + //////////////////////////////////////////////////////////////////////// + // EBusTraits + using MutexType = AZStd::recursive_mutex; + //////////////////////////////////////////////////////////////////////// + + virtual ~TerrainAreaSurfaceRequests() = default; + + //! Get the surfaces and weights from a gradient at a given position sorted into descending order of weight. + virtual void GetSurfaceWeights(const AZ::Vector3& inPosition, AzFramework::SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights) const = 0; + }; + + using TerrainAreaSurfaceRequestBus = AZ::EBus; +} // namespace Terrain diff --git a/Gems/Terrain/Code/Include/Terrain/Ebuses/TerrainGradientSurfaceListBus.h b/Gems/Terrain/Code/Include/Terrain/Ebuses/TerrainGradientSurfaceListBus.h new file mode 100644 index 0000000000..5734a6e023 --- /dev/null +++ b/Gems/Terrain/Code/Include/Terrain/Ebuses/TerrainGradientSurfaceListBus.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include + +#include + +namespace Terrain +{ + + //! This bus provides retrieval of information from Terrain Surfaces. + class TerrainAreaSurfaceRequests + : public AZ::ComponentBus + { + public: + //////////////////////////////////////////////////////////////////////// + // EBusTraits + using MutexType = AZStd::recursive_mutex; + //////////////////////////////////////////////////////////////////////// + + virtual ~TerrainAreaSurfaceRequests() = default; + + virtual void GetSurfaceWeights(const AZ::Vector3& inPosition, SurfaceData::SurfaceTagWeightMap& surfaceWeights) const = 0; + }; + + using TerrainAreaSurfaceRequestBus = AZ::EBus; +} // namespace Terrain diff --git a/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.cpp new file mode 100644 index 0000000000..2fbd6a4814 --- /dev/null +++ b/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.cpp @@ -0,0 +1,157 @@ +/* + * 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 Terrain +{ + void TerrainSurfaceGradientMapping::Reflect(AZ::ReflectContext* context) + { + if (auto serialize = azrtti_cast(context)) + { + serialize->Class() + ->Version(1) + ->Field("Gradient Entity", &TerrainSurfaceGradientMapping::m_gradientEntityId) + ->Field("Surface Tag", &TerrainSurfaceGradientMapping::m_surfaceTag) + ; + + if (auto edit = serialize->GetEditContext()) + { + edit->Class("Terrain Surface Gradient Mapping", "Mapping between a gradient and a surface.") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::Show) + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + + ->DataElement( + AZ::Edit::UIHandlers::Default, &TerrainSurfaceGradientMapping::m_gradientEntityId, "Gradient Entity", "ID of Entity providing a gradient.") + ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues) + ->UIElement("GradientPreviewer", "Previewer") + ->Attribute(AZ::Edit::Attributes::NameLabelOverride, "") + ->Attribute(AZ_CRC_CE("GradientEntity"), &TerrainSurfaceGradientMapping::m_gradientEntityId) + ->DataElement( + AZ::Edit::UIHandlers::Default, &TerrainSurfaceGradientMapping::m_surfaceTag, "Surface Tag", + "Surface type to map to this gradient.") + ; + } + } + } + + void TerrainSurfaceGradientListConfig::Reflect(AZ::ReflectContext* context) + { + TerrainSurfaceGradientMapping::Reflect(context); + + AZ::SerializeContext* serialize = azrtti_cast(context); + if (serialize) + { + serialize->Class() + ->Version(1) + ->Field("Mappings", &TerrainSurfaceGradientListConfig::m_gradientSurfaceMappings) + ; + + AZ::EditContext* edit = serialize->GetEditContext(); + if (edit) + { + edit->Class( + "Terrain Surface Gradient List Component", "Provide mapping between gradients and surfaces.") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::Show) + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + + ->DataElement( + AZ::Edit::UIHandlers::Default, &TerrainSurfaceGradientListConfig::m_gradientSurfaceMappings, "Gradient to Surface Mappings", "Maps Gradient Entities to Surfaces.") + ; + } + } + } + + void TerrainSurfaceGradientListComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services) + { + services.push_back(AZ_CRC_CE("TerrainSurfaceProviderService")); + } + + void TerrainSurfaceGradientListComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services) + { + services.push_back(AZ_CRC_CE("TerrainSurfaceProviderService")); + } + + void TerrainSurfaceGradientListComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services) + { + services.push_back(AZ_CRC("TerrainAreaService")); + } + + void TerrainSurfaceGradientListComponent::Reflect(AZ::ReflectContext* context) + { + TerrainSurfaceGradientListConfig::Reflect(context); + + AZ::SerializeContext* serialize = azrtti_cast(context); + if (serialize) + { + serialize->Class() + ->Version(0)->Field("Configuration", &TerrainSurfaceGradientListComponent::m_configuration) + ; + } + } + + TerrainSurfaceGradientListComponent::TerrainSurfaceGradientListComponent(const TerrainSurfaceGradientListConfig& configuration) + : m_configuration(configuration) + { + } + + void TerrainSurfaceGradientListComponent::Activate() + { + Terrain::TerrainAreaSurfaceRequestBus::Handler::BusConnect(GetEntityId()); + } + + void TerrainSurfaceGradientListComponent::Deactivate() + { + Terrain::TerrainAreaSurfaceRequestBus::Handler::BusDisconnect(); + } + + bool TerrainSurfaceGradientListComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig) + { + if (auto config = azrtti_cast(baseConfig)) + { + m_configuration = *config; + return true; + } + return false; + } + + bool TerrainSurfaceGradientListComponent::WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const + { + if (auto config = azrtti_cast(outBaseConfig)) + { + *config = m_configuration; + return true; + } + return false; + } + + void TerrainSurfaceGradientListComponent::GetSurfaceWeights(const AZ::Vector3& inPosition, AzFramework::SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights) const + { + outSurfaceWeights.clear(); + + const GradientSignal::GradientSampleParams params(AZ::Vector3(inPosition.GetX(), inPosition.GetY(), 0.0f)); + + for (const auto& mapping : m_configuration.m_gradientSurfaceMappings) + { + float weight = 0.0f; + GradientSignal::GradientRequestBus::EventResult(weight, mapping.m_gradientEntityId, &GradientSignal::GradientRequestBus::Events::GetValue, params); + + AzFramework::SurfaceData::SurfaceTagWeight tagWeight; + tagWeight.m_surfaceType = mapping.m_surfaceTag; + tagWeight.m_weight = weight; + outSurfaceWeights.emplace(tagWeight); + } + } +} // namespace Terrain diff --git a/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.h b/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.h new file mode 100644 index 0000000000..799038354c --- /dev/null +++ b/Gems/Terrain/Code/Source/Components/TerrainSurfaceGradientListComponent.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include + +#include + +namespace LmbrCentral +{ + template + class EditorWrappedComponentBase; +} + +namespace Terrain +{ + class TerrainSurfaceGradientMapping final + { + public: + AZ_CLASS_ALLOCATOR(TerrainSurfaceGradientMapping, AZ::SystemAllocator, 0); + AZ_RTTI(TerrainSurfaceGradientMapping, "{473AD2CE-F22A-45A9-803F-2192F3D9F2BF}"); + static void Reflect(AZ::ReflectContext* context); + + AZ::EntityId m_gradientEntityId; + SurfaceData::SurfaceTag m_surfaceTag; + }; + + class TerrainSurfaceGradientListConfig : public AZ::ComponentConfig + { + public: + AZ_CLASS_ALLOCATOR(TerrainSurfaceGradientListConfig, AZ::SystemAllocator, 0); + AZ_RTTI(TerrainSurfaceGradientListConfig, "{E9B083AD-8D30-47DA-8F8E-AA089BFA35E9}", AZ::ComponentConfig); + static void Reflect(AZ::ReflectContext* context); + + AZStd::vector m_gradientSurfaceMappings; + }; + + class TerrainSurfaceGradientListComponent + : public AZ::Component + , public Terrain::TerrainAreaSurfaceRequestBus::Handler + { + public: + template + friend class LmbrCentral::EditorWrappedComponentBase; + AZ_COMPONENT(TerrainSurfaceGradientListComponent, "{51F97C95-6B8A-4B06-B394-BD25BFCC8B7E}"); + static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services); + static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services); + static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services); + static void Reflect(AZ::ReflectContext* context); + + TerrainSurfaceGradientListComponent(const TerrainSurfaceGradientListConfig& configuration); + TerrainSurfaceGradientListComponent() = default; + ~TerrainSurfaceGradientListComponent() = default; + + ////////////////////////////////////////////////////////////////////////// + // AZ::Component interface implementation + void Activate() override; + void Deactivate() override; + bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override; + bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override; + + // TerrainAreaSurfaceRequestBus + void GetSurfaceWeights(const AZ::Vector3& inPosition, AzFramework::SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights) const override; + + private: + TerrainSurfaceGradientListConfig m_configuration; + }; +} // namespace Terrain diff --git a/Gems/Terrain/Code/Source/EditorComponents/EditorTerrainSurfaceGradientListComponent.cpp b/Gems/Terrain/Code/Source/EditorComponents/EditorTerrainSurfaceGradientListComponent.cpp new file mode 100644 index 0000000000..cf2c44225a --- /dev/null +++ b/Gems/Terrain/Code/Source/EditorComponents/EditorTerrainSurfaceGradientListComponent.cpp @@ -0,0 +1,22 @@ +/* + * 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 Terrain +{ + void EditorTerrainSurfaceGradientListComponent::Reflect(AZ::ReflectContext* context) + { + BaseClassType::ReflectSubClass(context, 1, + &LmbrCentral::EditorWrappedComponentBaseVersionConverter + ); + } +} diff --git a/Gems/Terrain/Code/Source/EditorComponents/EditorTerrainSurfaceGradientListComponent.h b/Gems/Terrain/Code/Source/EditorComponents/EditorTerrainSurfaceGradientListComponent.h new file mode 100644 index 0000000000..e2c5f1b280 --- /dev/null +++ b/Gems/Terrain/Code/Source/EditorComponents/EditorTerrainSurfaceGradientListComponent.h @@ -0,0 +1,32 @@ +/* + * 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 Terrain +{ + class EditorTerrainSurfaceGradientListComponent + : public LmbrCentral::EditorWrappedComponentBase + { + public: + using BaseClassType = LmbrCentral::EditorWrappedComponentBase; + AZ_EDITOR_COMPONENT(EditorTerrainSurfaceGradientListComponent, "{49831E91-A11F-4EFF-A824-6D85C284B934}", BaseClassType); + static void Reflect(AZ::ReflectContext* context); + + static constexpr const char* const s_categoryName = "Terrain"; + static constexpr const char* const s_componentName = "Terrain Surface Gradient List"; + static constexpr const char* const s_componentDescription = "Provides a mapping between gradients and surface tags for use by the terrain system."; + static constexpr const char* const s_icon = "Editor/Icons/Components/TerrainLayerSpawner.svg"; + static constexpr const char* const s_viewportIcon = "Editor/Icons/Components/Viewport/TerrainLayerSpawner.svg"; + static constexpr const char* const s_helpUrl = ""; + }; +} diff --git a/Gems/Terrain/Code/Source/EditorTerrainModule.cpp b/Gems/Terrain/Code/Source/EditorTerrainModule.cpp index 5305087694..9107ea8541 100644 --- a/Gems/Terrain/Code/Source/EditorTerrainModule.cpp +++ b/Gems/Terrain/Code/Source/EditorTerrainModule.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -23,6 +24,7 @@ namespace Terrain { Terrain::EditorTerrainHeightGradientListComponent::CreateDescriptor(), Terrain::EditorTerrainLayerSpawnerComponent::CreateDescriptor(), + Terrain::EditorTerrainSurfaceGradientListComponent::CreateDescriptor(), Terrain::EditorTerrainSystemComponent::CreateDescriptor(), Terrain::EditorTerrainWorldComponent::CreateDescriptor(), Terrain::EditorTerrainWorldDebuggerComponent::CreateDescriptor(), diff --git a/Gems/Terrain/Code/Source/TerrainModule.cpp b/Gems/Terrain/Code/Source/TerrainModule.cpp index 24b87b4ab3..6aeddc3cd5 100644 --- a/Gems/Terrain/Code/Source/TerrainModule.cpp +++ b/Gems/Terrain/Code/Source/TerrainModule.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include namespace Terrain @@ -30,6 +31,7 @@ namespace Terrain TerrainWorldRendererComponent::CreateDescriptor(), TerrainHeightGradientListComponent::CreateDescriptor(), TerrainLayerSpawnerComponent::CreateDescriptor(), + TerrainSurfaceGradientListComponent::CreateDescriptor(), TerrainSurfaceDataSystemComponent::CreateDescriptor(), }); } diff --git a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp index 46ac677dd1..821e0bd2e2 100644 --- a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp +++ b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp @@ -8,10 +8,17 @@ #include #include +#include #include #include #include +#include +#include +#include + +#include + using namespace Terrain; bool TerrainLayerPriorityComparator::operator()(const AZ::EntityId& layer1id, const AZ::EntityId& layer2id) const @@ -201,6 +208,7 @@ float TerrainSystem::GetHeightSynchronous(float x, float y, Sampler sampler, boo break; } + // For now, always set terrainExists to true, as we don't have a way to author data for terrain holes yet. if (terrainExistsPtr) { *terrainExistsPtr = terrainExists; @@ -291,33 +299,134 @@ AZ::Vector3 TerrainSystem::GetNormalFromFloats(float x, float y, Sampler sampler AzFramework::SurfaceData::SurfaceTagWeight TerrainSystem::GetMaxSurfaceWeight( - [[maybe_unused]] AZ::Vector3 position, [[maybe_unused]] Sampler sampleFilter, [[maybe_unused]] bool* terrainExistsPtr) const + const AZ::Vector3 position, Sampler sampleFilter, bool* terrainExistsPtr) const { - if (terrainExistsPtr) - { - *terrainExistsPtr = true; - } + return GetMaxSurfaceWeightFromFloats(position.GetX(), position.GetY(), sampleFilter, terrainExistsPtr); +} - return AzFramework::SurfaceData::SurfaceTagWeight(); +AzFramework::SurfaceData::SurfaceTagWeight TerrainSystem::GetMaxSurfaceWeightFromVector2(const AZ::Vector2& inPosition, Sampler sampleFilter, bool* terrainExistsPtr) const +{ + return GetMaxSurfaceWeightFromFloats(inPosition.GetX(), inPosition.GetY(), sampleFilter, terrainExistsPtr); } AzFramework::SurfaceData::SurfaceTagWeight TerrainSystem::GetMaxSurfaceWeightFromFloats( - [[maybe_unused]] float x, - [[maybe_unused]] float y, - [[maybe_unused]] Sampler sampleFilter, - [[maybe_unused]] bool* terrainExistsPtr) const + const float x, const float y, Sampler sampleFilter, bool* terrainExistsPtr) const { if (terrainExistsPtr) { *terrainExistsPtr = true; } - return AzFramework::SurfaceData::SurfaceTagWeight(); + AzFramework::SurfaceData::OrderedSurfaceTagWeightSet weightSet; + + GetOrderedSurfaceWeights(x, y, sampleFilter, weightSet, terrainExistsPtr); + + if (weightSet.empty()) + { + return {}; + } + + return *weightSet.begin(); } -const char* TerrainSystem::GetMaxSurfaceName( - [[maybe_unused]] AZ::Vector3 position, [[maybe_unused]] Sampler sampleFilter, [[maybe_unused]] bool* terrainExistsPtr) const +AZ::EntityId TerrainSystem::FindBestAreaEntityAtPosition(float x, float y, AZ::Aabb& bounds) const { + AZ::Vector3 inPosition = AZ::Vector3(x, y, 0); + + // Find the highest priority layer that encompasses this position + AZStd::shared_lock lock(m_areaMutex); + + // The areas are sorted into priority order: the first area that contains inPosition is the most suitable. + for (const auto& [areaId, areaBounds] : m_registeredAreas) + { + inPosition.SetZ(areaBounds.GetMin().GetZ()); + if (areaBounds.Contains(inPosition)) + { + bounds = areaBounds; + return areaId; + } + } + + return AZ::EntityId(); +} + +void TerrainSystem::GetOrderedSurfaceWeights( + const float x, + const float y, + [[maybe_unused]] Sampler sampler, + AzFramework::SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights, + bool* terrainExistsPtr) const +{ + AZ::Aabb bounds; + AZ::EntityId bestAreaId = FindBestAreaEntityAtPosition(x, y, bounds); + + if (terrainExistsPtr) + { + GetHeightFromFloats(x, y, AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT, terrainExistsPtr); + } + + outSurfaceWeights.clear(); + + if (!bestAreaId.IsValid()) + { + return; + } + + const AZ::Vector3 inPosition = AZ::Vector3(x, y, 0.0f); + + // Get all the surfaces with weights at the given point. + Terrain::TerrainAreaSurfaceRequestBus::Event( + bestAreaId, &Terrain::TerrainAreaSurfaceRequestBus::Events::GetSurfaceWeights, inPosition, outSurfaceWeights); +} + +void TerrainSystem::GetSurfaceWeights( + const AZ::Vector3& inPosition, + AzFramework::SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights, + Sampler sampleFilter, + bool* terrainExistsPtr) const +{ + if (terrainExistsPtr) + { + *terrainExistsPtr = true; + } + + GetOrderedSurfaceWeights(inPosition.GetX(), inPosition.GetY(), sampleFilter, outSurfaceWeights, terrainExistsPtr); +} + +void TerrainSystem::GetSurfaceWeightsFromVector2( + const AZ::Vector2& inPosition, + AzFramework::SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights, + Sampler sampleFilter, + bool* terrainExistsPtr) const +{ + // For now, always set terrainExists to true, as we don't have a way to author data for terrain holes yet. + if (terrainExistsPtr) + { + *terrainExistsPtr = true; + } + + GetOrderedSurfaceWeights(inPosition.GetX(), inPosition.GetY(), sampleFilter, outSurfaceWeights, terrainExistsPtr); +} + +void TerrainSystem::GetSurfaceWeightsFromFloats( + float x, + float y, + AzFramework::SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights, + Sampler sampleFilter, + bool* terrainExistsPtr) const +{ + // For now, always set terrainExists to true, as we don't have a way to author data for terrain holes yet. + if (terrainExistsPtr) + { + *terrainExistsPtr = true; + } + + GetOrderedSurfaceWeights(x, y, sampleFilter, outSurfaceWeights, terrainExistsPtr); +} + +const char* TerrainSystem::GetMaxSurfaceName([[maybe_unused]] AZ::Vector3 position, [[maybe_unused]] Sampler sampleFilter, [[maybe_unused]] bool* terrainExistsPtr) const +{ + // For now, always set terrainExists to true, as we don't have a way to author data for terrain holes yet. if (terrainExistsPtr) { *terrainExistsPtr = true; @@ -327,14 +436,6 @@ const char* TerrainSystem::GetMaxSurfaceName( } /* -void TerrainSystem::GetSurfaceWeights( - [[maybe_unused]] const AZ::Vector3& inPosition, - [[maybe_unused]] Sampler sampleFilter, - [[maybe_unused]] SurfaceData::SurfaceTagWeightMap& outSurfaceWeights) -{ - // TODO: implement -} - void TerrainSystem::GetSurfacePoint( const AZ::Vector3& inPosition, [[maybe_unused]] Sampler sampleFilter, SurfaceData::SurfacePoint& outSurfacePoint) { diff --git a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h index a9240e02a6..66c48850ef 100644 --- a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h +++ b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h @@ -70,9 +70,28 @@ namespace Terrain //! HOLE then *terrainExistsPtr will be set to false, //! otherwise *terrainExistsPtr will be set to true. AzFramework::SurfaceData::SurfaceTagWeight GetMaxSurfaceWeight( - AZ::Vector3 position, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const override; + const AZ::Vector3 position, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const override; + AzFramework::SurfaceData::SurfaceTagWeight GetMaxSurfaceWeightFromVector2( + const AZ::Vector2& inPosition, Sampler sampleFilter = Sampler::DEFAULT, bool* terrainExistsPtr = nullptr) const override; AzFramework::SurfaceData::SurfaceTagWeight GetMaxSurfaceWeightFromFloats( - float x, float y, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const override; + const float x, const float y, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const override; + + void GetSurfaceWeights( + const AZ::Vector3& inPosition, + AzFramework::SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights, + Sampler sampleFilter = Sampler::DEFAULT, + bool* terrainExistsPtr = nullptr) const override; + void GetSurfaceWeightsFromVector2( + const AZ::Vector2& inPosition, + AzFramework::SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights, + Sampler sampleFilter = Sampler::DEFAULT, + bool* terrainExistsPtr = nullptr) const override; + void GetSurfaceWeightsFromFloats( + float x, + float y, + AzFramework::SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights, + Sampler sampleFilter = Sampler::DEFAULT, + bool* terrainExistsPtr = nullptr) const override; //! Convenience function for low level systems that can't do a reverse lookup from Crc to string. Everyone else should use //! GetMaxSurfaceWeight or GetMaxSurfaceWeightFromFloats. Not available in the behavior context. Returns nullptr if the position is @@ -96,6 +115,13 @@ namespace Terrain private: void ClampPosition(float x, float y, AZ::Vector2& outPosition, AZ::Vector2& normalizedDelta) const; + AZ::EntityId FindBestAreaEntityAtPosition(float x, float y, AZ::Aabb& bounds) const; + void GetOrderedSurfaceWeights( + const float x, + const float y, + Sampler sampler, + AzFramework::SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights, + bool* terrainExistsPtr) const; float GetHeightSynchronous(float x, float y, Sampler sampler, bool* terrainExistsPtr) const; float GetTerrainAreaHeight(float x, float y, bool& terrainExists) const; AZ::Vector3 GetNormalSynchronous(float x, float y, Sampler sampler, bool* terrainExistsPtr) const; diff --git a/Gems/Terrain/Code/terrain_editor_shared_files.cmake b/Gems/Terrain/Code/terrain_editor_shared_files.cmake index d4719f46d5..efb68eca31 100644 --- a/Gems/Terrain/Code/terrain_editor_shared_files.cmake +++ b/Gems/Terrain/Code/terrain_editor_shared_files.cmake @@ -11,6 +11,8 @@ set(FILES Source/EditorComponents/EditorTerrainHeightGradientListComponent.h Source/EditorComponents/EditorTerrainLayerSpawnerComponent.cpp Source/EditorComponents/EditorTerrainLayerSpawnerComponent.h + Source/EditorComponents/EditorTerrainSurfaceGradientListComponent.cpp + Source/EditorComponents/EditorTerrainSurfaceGradientListComponent.h Source/EditorComponents/EditorTerrainWorldComponent.cpp Source/EditorComponents/EditorTerrainWorldComponent.h Source/EditorComponents/EditorTerrainWorldDebuggerComponent.cpp diff --git a/Gems/Terrain/Code/terrain_files.cmake b/Gems/Terrain/Code/terrain_files.cmake index 2c013fa332..6d190b7d5e 100644 --- a/Gems/Terrain/Code/terrain_files.cmake +++ b/Gems/Terrain/Code/terrain_files.cmake @@ -7,12 +7,15 @@ # set(FILES + Include/Terrain/Ebuses/TerrainAreaSurfaceRequestBus.h Source/Components/TerrainHeightGradientListComponent.cpp Source/Components/TerrainHeightGradientListComponent.h Source/Components/TerrainLayerSpawnerComponent.cpp Source/Components/TerrainLayerSpawnerComponent.h Source/Components/TerrainSurfaceDataSystemComponent.cpp Source/Components/TerrainSurfaceDataSystemComponent.h + Source/Components/TerrainSurfaceGradientListComponent.cpp + Source/Components/TerrainSurfaceGradientListComponent.h Source/Components/TerrainSystemComponent.cpp Source/Components/TerrainSystemComponent.h Source/Components/TerrainWorldComponent.cpp From aef1f01de2b598758af06c52458d219a0f61db53 Mon Sep 17 00:00:00 2001 From: Tommy Walton <82672795+amzn-tommy@users.noreply.github.com> Date: Tue, 5 Oct 2021 09:58:54 -0700 Subject: [PATCH 17/27] Expose OnModelReady to behavior context for hydra automation (#4331) * Expose OnModelReady to behavior context for hydra automation Signed-off-by: amzn-tommy * Adding assets used by the hydra test to Atom/TestData Signed-off-by: amzn-tommy * Attempt to fix line ending Signed-off-by: amzn-tommy * Moving behavior context for mesh notification bus to the component controller Signed-off-by: amzn-tommy * Changed the AssetManager DispatchEvents function to continously pump the AssetBus of queued functions until empty. This replicates the old behavior of the EBusQueuePolicy::Execute function that would continue to execute functions if new ones were added during the execution of the current queue. Split the TestFixture class from the AssetHandler and EBus handler for the DynamicSliceInstanceSpawnerTests and PrefabInstanceSpawnerTest. This avoids the AssetMananager destructor from deleting the test fixture if the call to UnregisterHandler is ever removed. This also allows the memory allocators to get online earlier. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removing an incorrect [[maybe_unused]] Signed-off-by: amzn-tommy * Moving incorrectly placed [[maybe_unused]] Signed-off-by: amzn-tommy Co-authored-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- .../DisplayVertexColor.material | 18 +++++++++++++ .../Objects/ModelHotReload/novertexcolor.fbx | 3 +++ .../Objects/ModelHotReload/sphere_5lods.fbx | 3 +++ .../Objects/ModelHotReload/vertexcolor.fbx | 3 +++ .../Source/Mesh/MeshComponentController.cpp | 25 ++++++++++++++++++- 5 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 Gems/Atom/TestData/TestData/Objects/ModelHotReload/DisplayVertexColor.material create mode 100644 Gems/Atom/TestData/TestData/Objects/ModelHotReload/novertexcolor.fbx create mode 100644 Gems/Atom/TestData/TestData/Objects/ModelHotReload/sphere_5lods.fbx create mode 100644 Gems/Atom/TestData/TestData/Objects/ModelHotReload/vertexcolor.fbx diff --git a/Gems/Atom/TestData/TestData/Objects/ModelHotReload/DisplayVertexColor.material b/Gems/Atom/TestData/TestData/Objects/ModelHotReload/DisplayVertexColor.material new file mode 100644 index 0000000000..104d675387 --- /dev/null +++ b/Gems/Atom/TestData/TestData/Objects/ModelHotReload/DisplayVertexColor.material @@ -0,0 +1,18 @@ +{ + "description": "", + "materialType": "Materials/Types/StandardMultilayerPBR.materialtype", + "parentMaterial": "", + "propertyLayoutVersion": 3, + "properties": { + "blend": { + "blendSource": "BlendMaskVertexColors", + "debugDrawMode": "FinalBlendWeights", + "enableLayer2": true, + "enableLayer3": true, + "textureMap": "" + }, + "parallax": { + "enable": false + } + } +} diff --git a/Gems/Atom/TestData/TestData/Objects/ModelHotReload/novertexcolor.fbx b/Gems/Atom/TestData/TestData/Objects/ModelHotReload/novertexcolor.fbx new file mode 100644 index 0000000000..abc518cf09 --- /dev/null +++ b/Gems/Atom/TestData/TestData/Objects/ModelHotReload/novertexcolor.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b6d860c6fc3703914716a97910899eca2e66927688690646f697c6246ac310fb +size 317340 diff --git a/Gems/Atom/TestData/TestData/Objects/ModelHotReload/sphere_5lods.fbx b/Gems/Atom/TestData/TestData/Objects/ModelHotReload/sphere_5lods.fbx new file mode 100644 index 0000000000..de03622834 --- /dev/null +++ b/Gems/Atom/TestData/TestData/Objects/ModelHotReload/sphere_5lods.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:91b8153f93e4773d872478fef40ff00c1b8d5f1ef13101cf62f81956e1c30107 +size 68800 diff --git a/Gems/Atom/TestData/TestData/Objects/ModelHotReload/vertexcolor.fbx b/Gems/Atom/TestData/TestData/Objects/ModelHotReload/vertexcolor.fbx new file mode 100644 index 0000000000..3bbbc29a33 --- /dev/null +++ b/Gems/Atom/TestData/TestData/Objects/ModelHotReload/vertexcolor.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2cf646a0a977c2edc5ee2ab6351ef633f194ce60c59ea3cb8359f71648db668e +size 374492 diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp index 6cdb44a9e1..12b14d8162 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp @@ -32,6 +32,23 @@ namespace AZ { namespace Render { + namespace Internal + { + struct MeshComponentNotificationBusHandler final + : public MeshComponentNotificationBus::Handler + , public AZ::BehaviorEBusHandler + { + AZ_EBUS_BEHAVIOR_BINDER( + MeshComponentNotificationBusHandler, "{8B8F4977-817F-4C7C-9141-0E5FF899E1BC}", AZ::SystemAllocator, OnModelReady); + + void OnModelReady( + [[maybe_unused]] const Data::Asset& modelAsset, + [[maybe_unused]] const Data::Instance& model) override + { + Call(FN_OnModelReady); + } + }; + } // namespace Internal namespace MeshComponentControllerVersionUtility { @@ -173,6 +190,12 @@ namespace AZ ->VirtualProperty("MinimumScreenCoverage", "GetMinimumScreenCoverage", "SetMinimumScreenCoverage") ->VirtualProperty("QualityDecayRate", "GetQualityDecayRate", "SetQualityDecayRate") ; + + behaviorContext->EBus("MeshComponentNotificationBus") + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) + ->Attribute(AZ::Script::Attributes::Category, "render") + ->Attribute(AZ::Script::Attributes::Module, "render") + ->Handler(); } } @@ -306,7 +329,7 @@ namespace AZ return model ? model->GetUvNames() : AZStd::unordered_set(); } - void MeshComponentController::OnMaterialsUpdated([[maybe_unused]] const MaterialAssignmentMap& materials) + void MeshComponentController::OnMaterialsUpdated(const MaterialAssignmentMap& materials) { if (m_meshFeatureProcessor) { From 256564a3e09a7fc677223fc47db9e0531b2981c6 Mon Sep 17 00:00:00 2001 From: Tommy Walton <82672795+amzn-tommy@users.noreply.github.com> Date: Tue, 5 Oct 2021 09:59:13 -0700 Subject: [PATCH 18/27] Model Hot-Reloading (#4304) * Added a ModelReloader class that handles reloading the hierarchy of assets in the correct order. A ModelReloaderSystem that is used to make sure there is only one ModelReloader at a time for a given asset. Modified the Model, ModelLodAsset, and Buffer assets to not automatically reload, and instead handle reloads manually via AssetCatalog events. Modified the MeshLoader to kick off a reload via the ModelReloaderSystem whenever a model asset is added or changed. Signed-off-by: amzn-tommy * Comment updates Signed-off-by: amzn-tommy * Minor naming and comment updates based on PR feedback Signed-off-by: amzn-tommy * Correcting previous commit. I flipped == to != when switching from count to find, when it should have stayed == Signed-off-by: amzn-tommy * Updating RenderCommon header Signed-off-by: amzn-tommy * Removing unneeded headers Signed-off-by: amzn-tommy * Reverting RayTracingFeatureProcessor change following Doug's guidance. This logic was tricky to get right initially, and leads to TDR when incorrect, so leaving as is. Signed-off-by: amzn-tommy * Removing a tab Signed-off-by: amzn-tommy * Added missing #include for AssetId Signed-off-by: amzn-tommy * Adding missing RTTI header Signed-off-by: amzn-tommy * Include ModelAsset definition intead of forward declaring it to avoid a static assert on Linux Signed-off-by: amzn-tommy --- .../Atom/Feature/Mesh/MeshFeatureProcessor.h | 15 ++ .../Mesh/ModelReloaderSystemInterface.h | 57 ++++++ .../Code/Source/CommonSystemComponent.cpp | 7 + .../Code/Source/CommonSystemComponent.h | 7 + .../Code/Source/Mesh/MeshFeatureProcessor.cpp | 68 ++++++- .../Common/Code/Source/Mesh/ModelReloader.cpp | 175 ++++++++++++++++++ .../Common/Code/Source/Mesh/ModelReloader.h | 74 ++++++++ .../Code/Source/Mesh/ModelReloaderSystem.cpp | 38 ++++ .../Code/Source/Mesh/ModelReloaderSystem.h | 50 +++++ .../Code/atom_feature_common_files.cmake | 5 + .../Include/Atom/RPI.Public/Model/Model.h | 4 + .../Atom/RPI.Reflect/Buffer/BufferAsset.h | 6 + .../Atom/RPI.Reflect/Model/ModelAsset.h | 6 + .../Atom/RPI.Reflect/Model/ModelLodAsset.h | 6 + .../Code/Source/RPI.Public/Model/Model.cpp | 22 +++ 15 files changed, 532 insertions(+), 8 deletions(-) create mode 100644 Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/ModelReloaderSystemInterface.h create mode 100644 Gems/Atom/Feature/Common/Code/Source/Mesh/ModelReloader.cpp create mode 100644 Gems/Atom/Feature/Common/Code/Source/Mesh/ModelReloader.h create mode 100644 Gems/Atom/Feature/Common/Code/Source/Mesh/ModelReloaderSystem.cpp create mode 100644 Gems/Atom/Feature/Common/Code/Source/Mesh/ModelReloaderSystem.h diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h index 389c5902f9..2ac184e2e0 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h @@ -14,10 +14,14 @@ #include #include #include +#include #include #include #include #include +#include + +#include namespace AZ { @@ -38,6 +42,7 @@ namespace AZ private: class MeshLoader : private Data::AssetBus::Handler + , private AzFramework::AssetCatalogEventBus::Handler { public: using ModelChangedEvent = MeshFeatureProcessorInterface::ModelChangedEvent; @@ -52,6 +57,15 @@ namespace AZ void OnAssetReady(Data::Asset asset) override; void OnAssetError(Data::Asset asset) override; + // AssetCatalogEventBus::Handler overrides... + void OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) override; + void OnCatalogAssetAdded(const AZ::Data::AssetId& assetId) override; + + void OnModelReloaded(Data::Asset asset); + ModelReloadedEvent::Handler m_modelReloadedEventHandler { [&](Data::Asset modelAsset) + { + OnModelReloaded(modelAsset); + } }; MeshFeatureProcessorInterface::ModelChangedEvent m_modelChangedEvent; Data::Asset m_modelAsset; MeshDataInstance* m_parent = nullptr; @@ -61,6 +75,7 @@ namespace AZ void Init(Data::Instance model); void BuildDrawPacketList(size_t modelLodIndex); void SetRayTracingData(); + void RemoveRayTracingData(); void SetSortKey(RHI::DrawItemSortKey sortKey); RHI::DrawItemSortKey GetSortKey() const; void SetMeshLodConfiguration(RPI::Cullable::LodConfiguration meshLodConfig); diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/ModelReloaderSystemInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/ModelReloaderSystemInterface.h new file mode 100644 index 0000000000..bf0ca6a1a3 --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/ModelReloaderSystemInterface.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include + +namespace AZ +{ + namespace Data + { + template + class Asset; + } + + namespace Render + { + using ModelReloadedEvent = Event>; + + //! A system that handles reloading the hierarchy of model assets in the correct order + class ModelReloaderSystemInterface + { + public: + AZ_RTTI(AZ::Render::ModelReloaderSystemInterface, "{E7E05B1F-8928-4A1B-B75D-3D5433E65BCA}"); + + ModelReloaderSystemInterface() + { + Interface::Register(this); + } + + virtual ~ModelReloaderSystemInterface() + { + Interface::Unregister(this); + } + + static ModelReloaderSystemInterface* Get() + { + return Interface::Get(); + } + + //! Requests a model reload and passes in a callback event handler for when the reload is finished + virtual void ReloadModel( + Data::Asset modelAsset, ModelReloadedEvent::Handler& onReloadedEventHandler) = 0; + + // Note that you have to delete these for safety reasons, you will trip a static_assert if you do not + AZ_DISABLE_COPY_MOVE(ModelReloaderSystemInterface); + }; + } // namespace Render +} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp index db49fba96f..22c5f37ff8 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp @@ -103,11 +103,15 @@ #include #include #include +#include namespace AZ { namespace Render { + CommonSystemComponent::CommonSystemComponent() = default; + CommonSystemComponent::~CommonSystemComponent() = default; + void CommonSystemComponent::Reflect(ReflectContext* context) { AuxGeomFeatureProcessor::Reflect(context); @@ -292,10 +296,13 @@ namespace AZ // setup handler for load pass template mappings m_loadTemplatesHandler = RPI::PassSystemInterface::OnReadyLoadTemplatesEvent::Handler([this]() { this->LoadPassTemplateMappings(); }); RPI::PassSystemInterface::Get()->ConnectEvent(m_loadTemplatesHandler); + + m_modelReloaderSystem = AZStd::make_unique(); } void CommonSystemComponent::Deactivate() { + m_modelReloaderSystem.reset(); m_loadTemplatesHandler.Disconnect(); AZ::RPI::FeatureProcessorFactory::Get()->UnregisterFeatureProcessor(); AZ::RPI::FeatureProcessorFactory::Get()->UnregisterFeatureProcessor(); diff --git a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.h b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.h index 766256dd36..b12ad3459c 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.h +++ b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.h @@ -20,12 +20,17 @@ namespace AZ { namespace Render { + class ModelReloaderSystem; + class CommonSystemComponent : public AZ::Component { public: AZ_COMPONENT(CommonSystemComponent, "{BFB8FE2B-C952-4D0C-8E32-4FE7C7A97757}"); + CommonSystemComponent(); + ~CommonSystemComponent(); + static void Reflect(AZ::ReflectContext* context); static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); @@ -44,6 +49,8 @@ namespace AZ RPI::PassSystemInterface::OnReadyLoadTemplatesEvent::Handler m_loadTemplatesHandler; + AZStd::unique_ptr m_modelReloaderSystem; + #if AZ_TRAIT_LUXCORE_SUPPORTED // LuxCore LuxCoreRenderer m_luxCore; diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp index cced38c3a7..c7fb19bc5d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -18,6 +19,8 @@ #include +#include + #include #include @@ -175,6 +178,7 @@ namespace AZ { if (meshHandle.IsValid()) { + meshHandle->m_meshLoader.reset(); meshHandle->DeInit(); m_transformService->ReleaseObjectId(meshHandle->m_objectId); @@ -487,10 +491,12 @@ namespace AZ } Data::AssetBus::Handler::BusConnect(modelAsset.GetId()); + AzFramework::AssetCatalogEventBus::Handler::BusConnect(); } MeshDataInstance::MeshLoader::~MeshLoader() { + AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); Data::AssetBus::Handler::BusDisconnect(); } @@ -533,6 +539,7 @@ namespace AZ if (model) { + m_parent->RemoveRayTracingData(); m_parent->Init(model); m_modelChangedEvent.Signal(AZStd::move(model)); } @@ -545,10 +552,51 @@ namespace AZ } } + + void MeshDataInstance::MeshLoader::OnModelReloaded(Data::Asset asset) + { + OnAssetReady(asset); + } + void MeshDataInstance::MeshLoader::OnAssetError(Data::Asset asset) { // Note: m_modelAsset and asset represents same asset, but only m_modelAsset contains the file path in its hint from serialization - AZ_Error("MeshDataInstance::MeshLoader", false, "Failed to load asset %s.", m_modelAsset.GetHint().c_str()); + AZ_Error( + "MeshDataInstance::MeshLoader", false, "Failed to load asset %s. It may be missing, or not be finished processing", + m_modelAsset.GetHint().c_str()); + + AzFramework::AssetSystemRequestBus::Broadcast( + &AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetByUuid, m_modelAsset.GetId().m_guid); + } + + void MeshDataInstance::MeshLoader::OnCatalogAssetChanged(const AZ::Data::AssetId& assetId) + { + if (assetId == m_modelAsset.GetId()) + { + Data::Asset modelAssetReference = m_modelAsset; + + // If the asset was modified, reload it + AZ::SystemTickBus::QueueFunction( + [=]() mutable + { + ModelReloaderSystemInterface::Get()->ReloadModel(modelAssetReference, m_modelReloadedEventHandler); + }); + } + } + + void MeshDataInstance::MeshLoader::OnCatalogAssetAdded(const AZ::Data::AssetId& assetId) + { + if (assetId == m_modelAsset.GetId()) + { + Data::Asset modelAssetReference = m_modelAsset; + + // If the asset didn't exist in the catalog when it first attempted to load, we need to try loading it again + AZ::SystemTickBus::QueueFunction( + [=]() mutable + { + ModelReloaderSystemInterface::Get()->ReloadModel(modelAssetReference, m_modelReloadedEventHandler); + }); + } } // MeshDataInstance... @@ -557,14 +605,8 @@ namespace AZ { m_scene->GetCullingScene()->UnregisterCullable(m_cullable); - // remove from ray tracing - RayTracingFeatureProcessor* rayTracingFeatureProcessor = m_scene->GetFeatureProcessor(); - if (rayTracingFeatureProcessor) - { - rayTracingFeatureProcessor->RemoveMesh(m_objectId); - } + RemoveRayTracingData(); - m_meshLoader.reset(); m_drawPacketListsByLod.clear(); m_materialAssignments.clear(); m_shaderResourceGroup = {}; @@ -951,6 +993,16 @@ namespace AZ rayTracingFeatureProcessor->SetMesh(m_objectId, m_model->GetModelAsset()->GetId(), subMeshes); } + void MeshDataInstance::RemoveRayTracingData() + { + // remove from ray tracing + RayTracingFeatureProcessor* rayTracingFeatureProcessor = m_scene->GetFeatureProcessor(); + if (rayTracingFeatureProcessor) + { + rayTracingFeatureProcessor->RemoveMesh(m_objectId); + } + } + void MeshDataInstance::SetSortKey(RHI::DrawItemSortKey sortKey) { m_sortKey = sortKey; diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/ModelReloader.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/ModelReloader.cpp new file mode 100644 index 0000000000..75df7c020b --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/ModelReloader.cpp @@ -0,0 +1,175 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include + +namespace AZ +{ + namespace Render + { + ModelReloader::ModelReloader( + Data::Asset modelAsset, RemoveModelFromReloaderSystemEvent::Handler& removeReloaderFromSystemHandler) + { + m_modelAsset.push_back(modelAsset); + m_pendingDependencyListStatus.reset(); + removeReloaderFromSystemHandler.Connect(m_onRemoveReloaderFromSystem); + + // Iterate over the model and track the assets that need to be reloaded + for (auto& modelLodAsset : modelAsset->GetLodAssets()) + { + for (auto& mesh : modelLodAsset->GetMeshes()) + { + for (auto& streamBufferInfo : mesh.GetStreamBufferInfoList()) + { + InsertMeshDependencyIfUnique(streamBufferInfo.m_bufferAssetView.GetBufferAsset()); + + } + InsertMeshDependencyIfUnique(mesh.GetIndexBufferAssetView().GetBufferAsset()); + } + m_modelDependencies.push_back(modelLodAsset); + } + + AZ_Assert( + m_meshDependencies.size() <= m_pendingDependencyListStatus.size(), + "There are more buffers used by the model %s than are supported by the ModelReloader.", modelAsset.GetHint().c_str()); + + m_state = State::WaitingForMeshDependencies; + ReloadDependenciesAndWait(); + } + + void ModelReloader::ConnectOnReloadedEventHandler(ModelReloadedEvent::Handler& onReloadedEventHandler) + { + onReloadedEventHandler.Connect(m_onModelReloaded); + } + + void ModelReloader::OnAssetReloaded(AZ::Data::Asset asset) + { + DependencyList& pendingDependencies = GetPendingDependencyList(); + + const Data::AssetId& reloadedAssetId = asset.GetId(); + + // Find the index of the asset that was reloaded + const auto matchesId = [reloadedAssetId](const Data::Asset& asset){ return asset.GetId() == reloadedAssetId;}; + const auto& iter = AZStd::find_if(AZStd::begin(pendingDependencies), AZStd::end(pendingDependencies), matchesId); + AZ_Assert( + iter != AZStd::end(pendingDependencies), + "ModelReloader - handling an AssetReloaded event for an asset that is not part of the dependency list."); + size_t currentIndex = AZStd::distance(AZStd::begin(pendingDependencies), iter); + + // Keep a reference to the newly reloaded asset to prevent it from being immediately released + pendingDependencies[currentIndex] = asset; + Data::AssetBus::MultiHandler::BusDisconnect(reloadedAssetId); + + // Clear the bit, now that it has been reloaded + m_pendingDependencyListStatus.reset(currentIndex); + + if (m_pendingDependencyListStatus.none()) + { + AdvanceToNextLevelOfHierarchy(); + } + } + + void ModelReloader::OnAssetReloadError(Data::Asset asset) + { + // An error is actually okay/expected in some situations. + // For example, if the 2nd UV set was removed, and we tried to reload the second uv set, the reload would fail. + // We want to treat it as a success, and mark that dependency as 'up to date' + OnAssetReloaded(asset); + } + + void ModelReloader::InsertMeshDependencyIfUnique(Data::Asset asset) + { + if (AZStd::find(AZStd::begin(m_meshDependencies), AZStd::end(m_meshDependencies), asset) == AZStd::end(m_meshDependencies)) + { + // Multiple meshes may reference the same buffer, so only add the dependency if it is unique + m_meshDependencies.push_back(asset); + } + } + + void ModelReloader::ReloadDependenciesAndWait() + { + // Get the current list of dependencies depending on the current state + DependencyList& dependencies = GetPendingDependencyList(); + + if (!m_pendingDependencyListStatus.none()) + { + AZ_Assert( + m_pendingDependencyListStatus.none(), + "ModelReloader attempting to add new dependencies while still waiting for other dependencies in the hierarchy to " + "load."); + } + if (dependencies.empty()) + { + // If the original model asset failed to load, it won't have any dependencies to reload + AdvanceToNextLevelOfHierarchy(); + } + AZ_Assert( + dependencies.size() <= m_pendingDependencyListStatus.size(), + "ModelReloader has more dependencies than can fit in the bitset. The size of m_pendingDependencyListStatus needs to be increased."); + + // Set all bits to 1 + m_pendingDependencyListStatus.set(); + // Clear the least significant n-bits + m_pendingDependencyListStatus <<= dependencies.size(); + // Set the least significant n-bits to 1, and the rest to 0 + m_pendingDependencyListStatus.flip(); + + // Reload all the assets + for (Data::Asset& dependencyAsset : dependencies) + { + Data::AssetBus::MultiHandler::BusConnect(dependencyAsset.GetId()); + dependencyAsset.Reload(); + } + } + + void ModelReloader::AdvanceToNextLevelOfHierarchy() + { + switch (m_state) + { + case State::WaitingForMeshDependencies: + m_state = State::WaitingForModelDependencies; + ReloadDependenciesAndWait(); + break; + case State::WaitingForModelDependencies: + m_state = State::WaitingForModel; + ReloadDependenciesAndWait(); + break; + case State::WaitingForModel: + Data::AssetBus::MultiHandler::BusDisconnect(); + // Since the model asset is finished reloading, orphan model from the instance database + // so that all of the buffer instances are re-created with the latest data + RPI::Model::TEMPOrphanFromDatabase(m_modelAsset.front()); + // Signal that the model is ready + m_onModelReloaded.Signal(m_modelAsset.front()); + // Remove this reloader from the ModelReloaderSystem + m_onRemoveReloaderFromSystem.Signal(m_modelAsset.front().GetId()); + delete this; + break; + } + } + + ModelReloader::DependencyList& ModelReloader::GetPendingDependencyList() + { + switch (m_state) + { + case State::WaitingForMeshDependencies: + return m_meshDependencies; + break; + case State::WaitingForModelDependencies: + return m_modelDependencies; + break; + case State::WaitingForModel: + default: + return m_modelAsset; + break; + } + } + } // namespace Render +} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/ModelReloader.h b/Gems/Atom/Feature/Common/Code/Source/Mesh/ModelReloader.h new file mode 100644 index 0000000000..6b4c493d52 --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/ModelReloader.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include + +namespace AZ +{ + namespace RPI + { + class ModelAsset; + } + + namespace Render + { + //! ModelReloader takes care of reloading Buffer, ModelLod, and Model assets in the correct order + //! The ModelReloaderSystem should be used to reload a model, rather than using a ModelReloader directly + class ModelReloader + : private Data::AssetBus::MultiHandler + { + using DependencyList = AZStd::vector>; + public: + AZ_RTTI(AZ::Render::ModelReloader, "{99B75A6A-62B6-490A-9953-029BE7D69452}"); + + ModelReloader() = default; + + //! Reload a model asset + //! @param modelAsset - the asset to be reloaded + //! @param removeReloaderFromSystemHandler - an event that will tell the ModelReloaderSystem when to remove the reloader because it is finished + ModelReloader(Data::Asset modelAsset, RemoveModelFromReloaderSystemEvent::Handler& removeReloaderFromSystemHandler); + + //! Connects a handler that will handle an event when the model is finished reloading + void ConnectOnReloadedEventHandler(ModelReloadedEvent::Handler& onReloadedEventHandler); + + private: + enum class State + { + WaitingForMeshDependencies, + WaitingForModelDependencies, + WaitingForModel + }; + + // Data::AssetBus::MultiHandler overrides... + void OnAssetReloaded(AZ::Data::Asset asset) override; + void OnAssetReloadError(Data::Asset asset) override; + + void InsertMeshDependencyIfUnique(Data::Asset asset); + void ReloadDependenciesAndWait(); + void AdvanceToNextLevelOfHierarchy(); + DependencyList& GetPendingDependencyList(); + + ModelReloadedEvent m_onModelReloaded; + RemoveModelFromReloaderSystemEvent m_onRemoveReloaderFromSystem; + + // Keep track of all the asset references for each level of the hierarchy + DependencyList m_modelAsset; + DependencyList m_meshDependencies; + DependencyList m_modelDependencies; + + AZStd::bitset<1024> m_pendingDependencyListStatus; + State m_state; + }; + + } // namespace Render +} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/ModelReloaderSystem.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/ModelReloaderSystem.cpp new file mode 100644 index 0000000000..017f0f3419 --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/ModelReloaderSystem.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include + +namespace AZ +{ + namespace Render + { + void ModelReloaderSystem::ReloadModel(Data::Asset modelAsset, ModelReloadedEvent::Handler& onReloadedEventHandler) + { + AZStd::scoped_lock lock(m_pendingReloadMutex); + if (m_pendingReloads.find(modelAsset.GetId()) == m_pendingReloads.end()) + { + ModelReloader* reloader = new ModelReloader(modelAsset, m_removeModelHandler); + m_pendingReloads[modelAsset.GetId()] = reloader; + } + + m_pendingReloads[modelAsset.GetId()]->ConnectOnReloadedEventHandler(onReloadedEventHandler); + } + + void ModelReloaderSystem::RemoveReloader(const Data::AssetId& assetId) + { + AZStd::scoped_lock lock(m_pendingReloadMutex); + // We don't delete the ModelReloader here, because its in the middle of signaling this RemoveReloader event. + // We only remove it from the pending reloads here. + // The ModelReloader will delete itself after it finishes firing this event. + m_pendingReloads.erase(assetId); + } + } // namespace Render +} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/ModelReloaderSystem.h b/Gems/Atom/Feature/Common/Code/Source/Mesh/ModelReloaderSystem.h new file mode 100644 index 0000000000..dbdc6c77b1 --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/ModelReloaderSystem.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include + +#include +#include +#include + +namespace AZ +{ + namespace Render + { + class ModelReloader; + + using RemoveModelFromReloaderSystemEvent = Event; + + class ModelReloaderSystem + : public ModelReloaderSystemInterface + { + public: + AZ_RTTI(Render::ModelReloaderSystem, "{8C85ECCD-B6C8-4949-B26C-9C4F1020F2B8}", Render::ModelReloaderSystemInterface); + + void ReloadModel(Data::Asset modelAsset, ModelReloadedEvent::Handler& onReloadedEventHandler) override; + + private: + void RemoveReloader(const Data::AssetId& assetId); + + // Keep track of all the pending reloads so there are no duplicates + AZStd::unordered_map m_pendingReloads; + AZStd::mutex m_pendingReloadMutex; + + RemoveModelFromReloaderSystemEvent::Handler m_removeModelHandler{ + [&](const Data::AssetId& assetId) + { + RemoveReloader(assetId); + } }; + + friend class ModelReloader; + }; + + } // namespace Render +} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake index 9372d6594a..18cdc273d2 100644 --- a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake +++ b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake @@ -26,6 +26,7 @@ set(FILES Include/Atom/Feature/ImageBasedLights/ImageBasedLightFeatureProcessor.h Include/Atom/Feature/LookupTable/LookupTableAsset.h Include/Atom/Feature/Mesh/MeshFeatureProcessor.h + Include/Atom/Feature/Mesh/ModelReloaderSystemInterface.h Include/Atom/Feature/PostProcessing/PostProcessingConstants.h Include/Atom/Feature/PostProcessing/SMAAFeatureProcessorInterface.h Include/Atom/Feature/PostProcess/PostFxLayerCategoriesConstants.h @@ -169,6 +170,10 @@ set(FILES Source/Math/MathFilter.cpp Source/Math/MathFilterDescriptor.h Source/Mesh/MeshFeatureProcessor.cpp + Source/Mesh/ModelReloader.cpp + Source/Mesh/ModelReloader.h + Source/Mesh/ModelReloaderSystem.cpp + Source/Mesh/ModelReloaderSystem.h Source/MorphTargets/MorphTargetComputePass.cpp Source/MorphTargets/MorphTargetComputePass.h Source/MorphTargets/MorphTargetDispatchItem.cpp diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Model/Model.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Model/Model.h index b94d2169bf..91a9a2d009 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Model/Model.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Model/Model.h @@ -37,6 +37,10 @@ namespace AZ static Data::Instance FindOrCreate(const Data::Asset& modelAsset); + //! Orphan the model, its lods, and all their buffers so that they can be replaced in the instance database + //! This is a temporary function, that will be removed once the Model/ModelAsset classes no longer need it + static void TEMPOrphanFromDatabase(const Data::Asset& modelAsset); + ~Model() = default; //! Blocks the CPU until the streaming upload is complete. Returns immediately if no diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Buffer/BufferAsset.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Buffer/BufferAsset.h index 4f4b2b340d..e6fe68b21e 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Buffer/BufferAsset.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Buffer/BufferAsset.h @@ -60,6 +60,12 @@ namespace AZ const AZStd::string& GetName() const; private: + // AssetData overrides... + bool HandleAutoReload() override + { + return false; + } + // Called by asset creators to assign the asset to a ready state. void SetReady(); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelAsset.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelAsset.h index dbcfc69d56..91d89ce719 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelAsset.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelAsset.h @@ -77,6 +77,12 @@ namespace AZ float& distanceNormalized, AZ::Vector3& normal) const; private: + // AssetData overrides... + bool HandleAutoReload() override + { + return false; + } + void SetReady(); AZ::Name m_name; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelLodAsset.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelLodAsset.h index 8c8edddfe1..4b09cf8d91 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelLodAsset.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Model/ModelLodAsset.h @@ -149,6 +149,12 @@ namespace AZ const AZ::Aabb& GetAabb() const; private: + // AssetData overrides... + bool HandleAutoReload() override + { + return false; + } + AZStd::vector m_meshes; AZ::Aabb m_aabb = AZ::Aabb::CreateNull(); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Model/Model.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Model/Model.cpp index 1ba17deb91..6549255d7e 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Model/Model.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Model/Model.cpp @@ -31,6 +31,28 @@ namespace AZ modelAsset); } + + void Model::TEMPOrphanFromDatabase(const Data::Asset& modelAsset) + { + for (auto& modelLodAsset : modelAsset->GetLodAssets()) + { + for(auto& mesh : modelLodAsset->GetMeshes()) + { + for (auto& streamBufferInfo : mesh.GetStreamBufferInfoList()) + { + Data::InstanceDatabase::Instance().TEMPOrphan( + Data::InstanceId::CreateFromAssetId(streamBufferInfo.m_bufferAssetView.GetBufferAsset().GetId())); + } + Data::InstanceDatabase::Instance().TEMPOrphan( + Data::InstanceId::CreateFromAssetId(mesh.GetIndexBufferAssetView().GetBufferAsset().GetId())); + } + Data::InstanceDatabase::Instance().TEMPOrphan(Data::InstanceId::CreateFromAssetId(modelLodAsset.GetId())); + } + + Data::InstanceDatabase::Instance().TEMPOrphan( + Data::InstanceId::CreateFromAssetId(modelAsset.GetId())); + } + size_t Model::GetLodCount() const { return m_lods.size(); From 430b5682b7be05d63b8079c0d7a302a6315bb619 Mon Sep 17 00:00:00 2001 From: Junbo Liang <68558268+junbo75@users.noreply.github.com> Date: Tue, 5 Oct 2021 11:03:53 -0700 Subject: [PATCH 19/27] Update the GameLift gem CDK application for supporting FlexMatch (#4335) Signed-off-by: Junbo Liang --- .../aws_gamelift/aws_gamelift_construct.py | 1 + .../cdk/aws_gamelift/flexmatch/__init__.py | 6 ++ .../flexmatch/flexmatch_configurations.py | 30 ++++++++++ .../cdk/aws_gamelift/flexmatch/matchmaking.py | 60 +++++++++++++++++++ .../game_session_queue/__init__.py | 6 ++ .../game_session_queue/game_session_queue.py | 43 +++++++++++++ .../cdk/aws_gamelift/gamelift_stack.py | 53 +++++----------- 7 files changed, 162 insertions(+), 37 deletions(-) create mode 100644 Gems/AWSGameLift/cdk/aws_gamelift/flexmatch/__init__.py create mode 100644 Gems/AWSGameLift/cdk/aws_gamelift/flexmatch/flexmatch_configurations.py create mode 100644 Gems/AWSGameLift/cdk/aws_gamelift/flexmatch/matchmaking.py create mode 100644 Gems/AWSGameLift/cdk/aws_gamelift/game_session_queue/__init__.py create mode 100644 Gems/AWSGameLift/cdk/aws_gamelift/game_session_queue/game_session_queue.py diff --git a/Gems/AWSGameLift/cdk/aws_gamelift/aws_gamelift_construct.py b/Gems/AWSGameLift/cdk/aws_gamelift/aws_gamelift_construct.py index 69f74e709e..67fa2aa054 100644 --- a/Gems/AWSGameLift/cdk/aws_gamelift/aws_gamelift_construct.py +++ b/Gems/AWSGameLift/cdk/aws_gamelift/aws_gamelift_construct.py @@ -52,6 +52,7 @@ class AWSGameLift(core.Construct): stack_name=stack_name, fleet_configurations=fleet_configurations, create_game_session_queue=self.node.try_get_context('create_game_session_queue') == 'true', + flex_match=self.node.try_get_context('flex_match') == 'true', description=f'Contains resources for the AWS GameLift Gem stack as part of the {project_name} project', tags=tags, env=env diff --git a/Gems/AWSGameLift/cdk/aws_gamelift/flexmatch/__init__.py b/Gems/AWSGameLift/cdk/aws_gamelift/flexmatch/__init__.py new file mode 100644 index 0000000000..50cbb262dd --- /dev/null +++ b/Gems/AWSGameLift/cdk/aws_gamelift/flexmatch/__init__.py @@ -0,0 +1,6 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. +For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" diff --git a/Gems/AWSGameLift/cdk/aws_gamelift/flexmatch/flexmatch_configurations.py b/Gems/AWSGameLift/cdk/aws_gamelift/flexmatch/flexmatch_configurations.py new file mode 100644 index 0000000000..436089b2c0 --- /dev/null +++ b/Gems/AWSGameLift/cdk/aws_gamelift/flexmatch/flexmatch_configurations.py @@ -0,0 +1,30 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. +For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + +# Matchmaking rule formatted as a JSON string. +# Comments are not allowed in JSON, but most elements support a description field. +# For instructions on designing Matchmaking rule sets, please check: +# https://docs.aws.amazon.com/gamelift/latest/flexmatchguide/match-design-ruleset.html +RULE_SET_BODY = '{"ruleLanguageVersion":"1.0","teams":[{"name":"Players","maxPlayers":4,"minPlayers":2}]}' + +# A flag that determines whether a match that was created with this configuration +# must be accepted by the matched players. +ACCEPTANCE_REQUIRED = False + +# The maximum duration, in seconds, that a matchmaking ticket can remain in process before timing out. +# Requests that fail due to timing out can be resubmitted as needed. +REQUEST_TIMEOUT_SECONDS = 300 + +# The number of player slots in a match to keep open for future players. +# This parameter is not used if FlexMatchMode is set to STANDALONE. +ADDITIONAL_PLAYER_COUNT = 2 + +# The method used to backfill game sessions that are created with this matchmaking configuration. +# Specify MANUAL when your game manages backfill requests manually or does not use the match backfill feature. +# Specify AUTOMATIC to have GameLift create a StartMatchBackfill request whenever a game session has one or more +# open slots. +BACKFILL_MODE = 'AUTOMATIC' diff --git a/Gems/AWSGameLift/cdk/aws_gamelift/flexmatch/matchmaking.py b/Gems/AWSGameLift/cdk/aws_gamelift/flexmatch/matchmaking.py new file mode 100644 index 0000000000..abdaef6713 --- /dev/null +++ b/Gems/AWSGameLift/cdk/aws_gamelift/flexmatch/matchmaking.py @@ -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 +""" + +import typing + +from aws_cdk import ( + core, + aws_gamelift as gamelift +) + +from . import flexmatch_configurations + +FLEX_MATCH_MODE = 'WITH_QUEUE' + + +class MatchmakingResoures: + """ + Create a matchmaking rule set and matchmaking configuration for Gamelift FlexMatch. + For more information about Gamelift FlexMatch, please check + https://docs.aws.amazon.com/gamelift/latest/flexmatchguide/match-intro.html + """ + def __init__(self, stack: core.Stack, game_session_queue_arns: typing.List[str]): + rule_set = gamelift.CfnMatchmakingRuleSet( + scope=stack, + id='MatchmakingRuleSet', + name=f'{stack.stack_name}-MatchmakingRuleSet', + rule_set_body=flexmatch_configurations.RULE_SET_BODY + ) + + matchmaking_configuration = gamelift.CfnMatchmakingConfiguration( + scope=stack, + id='MatchmakingConfiguration', + acceptance_required=flexmatch_configurations.ACCEPTANCE_REQUIRED, + name=f'{stack.stack_name}-MatchmakingConfiguration', + request_timeout_seconds=flexmatch_configurations.REQUEST_TIMEOUT_SECONDS, + rule_set_name=rule_set.name, + additional_player_count=flexmatch_configurations.ADDITIONAL_PLAYER_COUNT, + backfill_mode=flexmatch_configurations.BACKFILL_MODE, + flex_match_mode=FLEX_MATCH_MODE, + game_session_queue_arns=game_session_queue_arns if len(game_session_queue_arns) else None + ) + matchmaking_configuration.node.add_dependency(rule_set) + + # Export the matchmaking rule set and configuration names as stack outputs + core.CfnOutput( + stack, + id='MatchmakingRuleSetName', + description='Name of the matchmaking rule set', + export_name=f'{stack.stack_name}:MatchmakingRuleSet', + value=rule_set.name) + core.CfnOutput( + stack, + id='MatchmakingConfigurationName', + description='Name of the matchmaking configuration', + export_name=f'{stack.stack_name}:MatchmakingConfiguration', + value=matchmaking_configuration.name) diff --git a/Gems/AWSGameLift/cdk/aws_gamelift/game_session_queue/__init__.py b/Gems/AWSGameLift/cdk/aws_gamelift/game_session_queue/__init__.py new file mode 100644 index 0000000000..50cbb262dd --- /dev/null +++ b/Gems/AWSGameLift/cdk/aws_gamelift/game_session_queue/__init__.py @@ -0,0 +1,6 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. +For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" diff --git a/Gems/AWSGameLift/cdk/aws_gamelift/game_session_queue/game_session_queue.py b/Gems/AWSGameLift/cdk/aws_gamelift/game_session_queue/game_session_queue.py new file mode 100644 index 0000000000..3b06359b68 --- /dev/null +++ b/Gems/AWSGameLift/cdk/aws_gamelift/game_session_queue/game_session_queue.py @@ -0,0 +1,43 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. +For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" +import typing + +from aws_cdk import ( + core, + aws_gamelift as gamelift +) + + +class GameSessionQueueResources: + """ + Create a game session queue which fulfills game session placement requests using the fleets. + For more information about Gamelift game session queues, please check + https://docs.aws.amazon.com/gamelift/latest/developerguide/queues-intro.html + """ + def __init__(self, stack: core.Stack, destinations: typing.List): + self._game_session_queue = gamelift.CfnGameSessionQueue( + scope=stack, + id=f'{stack.stack_name}-GameLiftQueue', + name=f'{stack.stack_name}-GameLiftQueue', + destinations=[ + gamelift.CfnGameSessionQueue.DestinationProperty( + destination_arn=resource_arn + ) for resource_arn in destinations + ] + ) + + # Export the game session queue name as a stack output + core.CfnOutput( + scope=stack, + id='GameSessionQueue', + description='Name of the game session queue', + export_name=f'{stack.stack_name}:GameSessionQueue', + value=self._game_session_queue.name) + + @property + def game_session_queue_arn(self) -> str: + return self._game_session_queue.attr_arn diff --git a/Gems/AWSGameLift/cdk/aws_gamelift/gamelift_stack.py b/Gems/AWSGameLift/cdk/aws_gamelift/gamelift_stack.py index b6cfa44d8a..e2e115fe38 100644 --- a/Gems/AWSGameLift/cdk/aws_gamelift/gamelift_stack.py +++ b/Gems/AWSGameLift/cdk/aws_gamelift/gamelift_stack.py @@ -5,10 +5,13 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import typing +from aws_cdk import ( + core, + aws_gamelift as gamelift +) -from aws_cdk import core -from aws_cdk import aws_gamelift as gamelift +from .flexmatch import matchmaking +from .game_session_queue import game_session_queue class GameLiftStack(core.Stack): @@ -19,7 +22,9 @@ class GameLiftStack(core.Stack): """ def __init__(self, scope: core.Construct, id_: str, stack_name: str, fleet_configurations: dict, - create_game_session_queue: bool, **kwargs) -> None: + create_game_session_queue: bool, + flex_match: bool, + **kwargs) -> None: super().__init__(scope, id_, **kwargs) self._stack_name = stack_name @@ -50,7 +55,7 @@ class GameLiftStack(core.Stack): queue_destinations.append(destination_arn) # Export the GameLift fleet ids as a stack output - fleets_output = core.CfnOutput( + core.CfnOutput( self, id='GameLiftFleets', description='List of GameLift fleet ids', @@ -58,17 +63,13 @@ class GameLiftStack(core.Stack): value=','.join(fleet_ids) ) - if create_game_session_queue: - # Create a game session queue which fulfills game session placement requests using the fleets - game_session_queue = self._create_game_session_queue(queue_destinations) + game_session_queue_arns = [] + if flex_match or create_game_session_queue: + queue = game_session_queue.GameSessionQueueResources(self, queue_destinations) + game_session_queue_arns.append(queue.game_session_queue_arn) - # Export the game session queue name as a stack output - game_session_queue_output = core.CfnOutput( - self, - id='GameSessionQueue', - description='Name of the game session queue', - export_name=f'{self._stack_name}:GameSessionQueue', - value=game_session_queue.name) + if flex_match: + matchmaking.MatchmakingResoures(self, game_session_queue_arns) def _create_fleet(self, fleet_configuration: dict, identifier: int) -> gamelift.CfnFleet: """ @@ -155,25 +156,3 @@ class GameLiftStack(core.Stack): ) return alias - - def _create_game_session_queue(self, destinations: typing.List) -> gamelift.CfnGameSessionQueue: - """ - Create a placement queue that processes requests for new game sessions. - :param destinations: Destinations of the queue. - :return: Generated GameLift game session queue. - """ - game_session_queue = gamelift.CfnGameSessionQueue( - self, - id=f'{self._stack_name}-GameLiftQueue', - name=f'{self._stack_name}-game-session-queue', - destinations=[ - gamelift.CfnGameSessionQueue.DestinationProperty( - destination_arn=resource_arn - ) for resource_arn in destinations - ] - ) - - return game_session_queue - - - From bf7ae12402a748bb2f053c2f28d3546db4404dc5 Mon Sep 17 00:00:00 2001 From: Adi Bar-Lev <82479970+Adi-Amazon@users.noreply.github.com> Date: Tue, 5 Oct 2021 14:14:08 -0400 Subject: [PATCH 20/27] Hair - Adding the Hair Gem to the automated testing (#4498) * Hair - Adding the Hair Gem to the automated testing Signed-off-by: Adi-Amazon * Hair - added FP protection when not initialized Signed-off-by: Adi-Amazon * Hair - renaming shader options for longtitude / azimuth contribution separation Signed-off-by: Adi-Amazon --- .../Config/shader_global_build_options.json | 12 +++++++++--- AutomatedTesting/Gem/Code/enabled_gems.cmake | 4 +--- .../Registry/assets_scan_folders.setreg | 8 ++++++++ .../Assets/Shaders/HairLightingEquations.azsli | 17 ++++++++--------- .../Code/Passes/HairPPLLResolvePass.cpp | 5 ++--- .../Code/Rendering/HairFeatureProcessor.cpp | 11 ++++++++--- .../Code/Rendering/HairGlobalSettings.cpp | 12 +++++------- .../Code/Rendering/HairGlobalSettings.h | 5 ++--- 8 files changed, 43 insertions(+), 31 deletions(-) diff --git a/AutomatedTesting/Config/shader_global_build_options.json b/AutomatedTesting/Config/shader_global_build_options.json index 08e4d7f502..1aacb05575 100644 --- a/AutomatedTesting/Config/shader_global_build_options.json +++ b/AutomatedTesting/Config/shader_global_build_options.json @@ -3,9 +3,15 @@ "Version": 1, "ClassName": "GlobalBuildOptions", "ClassData": { - "ShaderCompilerArguments" : { - "DefaultMatrixOrder" : "Row", - "AzslcAdditionalFreeArguments" : "--strip-unused-srgs" + "ShaderCompilerArguments": { + "DefaultMatrixOrder": "Row", + "AzslcAdditionalFreeArguments": "--strip-unused-srgs" + }, + "PreprocessorOptions": { + "predefinedMacros": [ "AZSL=17" ], + "projectIncludePaths": [ + "Gems/AtomTressFX/Assets/Shaders" + ] } } } \ No newline at end of file diff --git a/AutomatedTesting/Gem/Code/enabled_gems.cmake b/AutomatedTesting/Gem/Code/enabled_gems.cmake index bae8afabb1..0d281661b9 100644 --- a/AutomatedTesting/Gem/Code/enabled_gems.cmake +++ b/AutomatedTesting/Gem/Code/enabled_gems.cmake @@ -24,6 +24,7 @@ set(ENABLED_GEMS Camera EMotionFX + AtomTressFX PhysX CameraFramework StartingPointMovement @@ -52,9 +53,6 @@ set(ENABLED_GEMS AWSCore AWSClientAuth AWSMetrics - - - AudioSystem ) diff --git a/AutomatedTesting/Registry/assets_scan_folders.setreg b/AutomatedTesting/Registry/assets_scan_folders.setreg index 91061f3337..c74ba6703e 100644 --- a/AutomatedTesting/Registry/assets_scan_folders.setreg +++ b/AutomatedTesting/Registry/assets_scan_folders.setreg @@ -51,6 +51,14 @@ [ "Gems/UiBasics" ] + }, + "Hair": + { + "SourcePaths": + [ + "Gems/AtomTressFX/Assets", + "Gems/AtomTressFX/Assets/Passes" + ] } } } diff --git a/Gems/AtomTressFX/Assets/Shaders/HairLightingEquations.azsli b/Gems/AtomTressFX/Assets/Shaders/HairLightingEquations.azsli index cbab545c2d..83ebc04521 100644 --- a/Gems/AtomTressFX/Assets/Shaders/HairLightingEquations.azsli +++ b/Gems/AtomTressFX/Assets/Shaders/HairLightingEquations.azsli @@ -57,9 +57,8 @@ option bool o_enableMarschner_R = true; option bool o_enableMarschner_TRT = true; option bool o_enableMarschner_TT = true; -option bool o_enableDiffuseLobe = true; -option bool o_enableSpecularLobe = true; -option bool o_enableTransmittanceLobe = true; +option bool o_enableLongtitudeCoeff = true; +option bool o_enableAzimuthCoeff = true; //------------------------------------------------------------------------------ // Longitudinal functions (M_R, M_TT, M_RTR) @@ -196,8 +195,8 @@ float3 HairMarschnerBSDF(Surface surface, LightingData lightingData, const float // R Path - single reflection from the hair towards the eye. if (o_enableMarschner_R) { - float lighting_R = o_enableDiffuseLobe ? M_R(surface, Lh, sinLiPlusSinLr) : 1.0f; - if (o_enableSpecularLobe) + float lighting_R = o_enableLongtitudeCoeff ? M_R(surface, Lh, sinLiPlusSinLr) : 1.0f; + if (o_enableAzimuthCoeff) lighting_R *= N_R(surface, cos_O2, Wi, Wr, f0); // The following lines are a cheap method to get occluded reflection by accoounting @@ -221,8 +220,8 @@ float3 HairMarschnerBSDF(Surface surface, LightingData lightingData, const float // on the average thickness. if (o_enableMarschner_TT) { - float3 lighting_TT = o_enableDiffuseLobe ? M_TT(surface, Lh, sinLiPlusSinLr) : float3(1.0f, 1.0f, 1.0f); - if (o_enableSpecularLobe) + float3 lighting_TT = o_enableLongtitudeCoeff ? M_TT(surface, Lh, sinLiPlusSinLr) : float3(1.0f, 1.0f, 1.0f); + if (o_enableAzimuthCoeff) lighting_TT *= N_TT(surface, n2, cos_O, cos_O2, cos_Ld, f0); // Reduce back transmittance based on the thickness of the hair @@ -234,8 +233,8 @@ float3 HairMarschnerBSDF(Surface surface, LightingData lightingData, const float // the hair towards the eye. if (o_enableMarschner_TRT) { - float3 lighting_TRT = o_enableDiffuseLobe ? M_TRT(surface, Lh, sinLiPlusSinLr) : float3(1.0f, 1.0f, 1.0f); - if (o_enableSpecularLobe) + float3 lighting_TRT = o_enableLongtitudeCoeff ? M_TRT(surface, Lh, sinLiPlusSinLr) : float3(1.0f, 1.0f, 1.0f); + if (o_enableAzimuthCoeff) lighting_TRT *= N_TRT(surface, cos_O, cos_Ld, f0); lighting += lighting_TRT; } diff --git a/Gems/AtomTressFX/Code/Passes/HairPPLLResolvePass.cpp b/Gems/AtomTressFX/Code/Passes/HairPPLLResolvePass.cpp index 0dc3b62c45..fa643a5488 100644 --- a/Gems/AtomTressFX/Code/Passes/HairPPLLResolvePass.cpp +++ b/Gems/AtomTressFX/Code/Passes/HairPPLLResolvePass.cpp @@ -47,9 +47,8 @@ namespace AZ shaderOption.SetValue(AZ::Name("o_enableMarschner_R"), AZ::RPI::ShaderOptionValue{ m_hairGlobalSettings.m_enableMarschner_R }); shaderOption.SetValue(AZ::Name("o_enableMarschner_TRT"), AZ::RPI::ShaderOptionValue{ m_hairGlobalSettings.m_enableMarschner_TRT }); shaderOption.SetValue(AZ::Name("o_enableMarschner_TT"), AZ::RPI::ShaderOptionValue{ m_hairGlobalSettings.m_enableMarschner_TT }); - shaderOption.SetValue(AZ::Name("o_enableDiffuseLobe"), AZ::RPI::ShaderOptionValue{ m_hairGlobalSettings.m_enableDiffuseLobe }); - shaderOption.SetValue(AZ::Name("o_enableSpecularLobe"), AZ::RPI::ShaderOptionValue{ m_hairGlobalSettings.m_enableSpecularLobe }); - shaderOption.SetValue(AZ::Name("o_enableTransmittanceLobe"), AZ::RPI::ShaderOptionValue{ m_hairGlobalSettings.m_enableTransmittanceLobe }); + shaderOption.SetValue(AZ::Name("o_enableLongtitudeCoeff"), AZ::RPI::ShaderOptionValue{ m_hairGlobalSettings.m_enableLongtitudeCoeff }); + shaderOption.SetValue(AZ::Name("o_enableAzimuthCoeff"), AZ::RPI::ShaderOptionValue{ m_hairGlobalSettings.m_enableAzimuthCoeff }); m_shaderOptions = shaderOption.GetShaderVariantKeyFallbackValue(); } diff --git a/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp b/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp index 04f71a79c8..e4f1b02a88 100644 --- a/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp +++ b/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp @@ -135,6 +135,11 @@ namespace AZ void HairFeatureProcessor::EnablePasses(bool enable) { + if (!m_initialized) + { + return; + } + for (auto& [passName, pass] : m_computePasses) { pass->SetEnabled(enable); @@ -339,14 +344,14 @@ namespace AZ resultSuccess &= InitPPLLFillPass(); resultSuccess &= InitPPLLResolvePass(); + m_initialized = resultSuccess; + // Don't enable passes if no hair object was added yet (depending on activation order) - if (m_hairRenderObjects.empty()) + if (m_initialized && m_hairRenderObjects.empty()) { EnablePasses(false); } - m_initialized = resultSuccess; - // this might not be an error - if the pass system is still empty / minimal // and these passes are not part of the minimal pipeline, they will not // be created. diff --git a/Gems/AtomTressFX/Code/Rendering/HairGlobalSettings.cpp b/Gems/AtomTressFX/Code/Rendering/HairGlobalSettings.cpp index df8b6e6a37..d26ca12336 100644 --- a/Gems/AtomTressFX/Code/Rendering/HairGlobalSettings.cpp +++ b/Gems/AtomTressFX/Code/Rendering/HairGlobalSettings.cpp @@ -21,7 +21,7 @@ namespace AZ if (auto serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(2) + ->Version(3) ->Field("EnableShadows", &HairGlobalSettings::m_enableShadows) ->Field("EnableDirectionalLights", &HairGlobalSettings::m_enableDirectionalLights) ->Field("EnablePunctualLights", &HairGlobalSettings::m_enablePunctualLights) @@ -31,9 +31,8 @@ namespace AZ ->Field("EnableMarschner_R", &HairGlobalSettings::m_enableMarschner_R) ->Field("EnableMarschner_TRT", &HairGlobalSettings::m_enableMarschner_TRT) ->Field("EnableMarschner_TT", &HairGlobalSettings::m_enableMarschner_TT) - ->Field("EnableDiffuseLobe", &HairGlobalSettings::m_enableDiffuseLobe) - ->Field("EnableSpecularLobe", &HairGlobalSettings::m_enableSpecularLobe) - ->Field("EnableTransmittanceLobe", &HairGlobalSettings::m_enableTransmittanceLobe) + ->Field("EnableLongtitudeCoeff", &HairGlobalSettings::m_enableLongtitudeCoeff) + ->Field("EnableAzimuthCoeff", &HairGlobalSettings::m_enableAzimuthCoeff) ; if (auto editContext = serializeContext->GetEditContext()) @@ -51,9 +50,8 @@ namespace AZ ->DataElement(AZ::Edit::UIHandlers::Default, &HairGlobalSettings::m_enableMarschner_R, "Enable Marschner R", "Enable Marschner R.") ->DataElement(AZ::Edit::UIHandlers::Default, &HairGlobalSettings::m_enableMarschner_TRT, "Enable Marschner TRT", "Enable Marschner TRT.") ->DataElement(AZ::Edit::UIHandlers::Default, &HairGlobalSettings::m_enableMarschner_TT, "Enable Marschner TT", "Enable Marschner TT.") - ->DataElement(AZ::Edit::UIHandlers::Default, &HairGlobalSettings::m_enableDiffuseLobe, "Enable Diffuse Lobe", "Enable Diffuse Lobe.") - ->DataElement(AZ::Edit::UIHandlers::Default, &HairGlobalSettings::m_enableSpecularLobe, "Enable Specular Lobe", "Enable Specular Lobe.") - ->DataElement(AZ::Edit::UIHandlers::Default, &HairGlobalSettings::m_enableTransmittanceLobe, "Enable Transmittance Lobe", "Enable Transmittance Lobe.") + ->DataElement(AZ::Edit::UIHandlers::Default, &HairGlobalSettings::m_enableLongtitudeCoeff, "Enable Longtitude", "Enable Longtitude Contribution") + ->DataElement(AZ::Edit::UIHandlers::Default, &HairGlobalSettings::m_enableAzimuthCoeff, "Enable Azimuth", "Enable Azimuth Contribution") ; } } diff --git a/Gems/AtomTressFX/Code/Rendering/HairGlobalSettings.h b/Gems/AtomTressFX/Code/Rendering/HairGlobalSettings.h index c7cf1e3bf4..1297f8f1bc 100644 --- a/Gems/AtomTressFX/Code/Rendering/HairGlobalSettings.h +++ b/Gems/AtomTressFX/Code/Rendering/HairGlobalSettings.h @@ -35,9 +35,8 @@ namespace AZ bool m_enableMarschner_R = true; bool m_enableMarschner_TRT = true; bool m_enableMarschner_TT = true; - bool m_enableDiffuseLobe = true; - bool m_enableSpecularLobe = true; - bool m_enableTransmittanceLobe = true; + bool m_enableLongtitudeCoeff = true; + bool m_enableAzimuthCoeff = true; }; } // namespace Hair } // namespace Render From df419a09902a1abb9645764c440aeb138d66b365 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Tue, 5 Oct 2021 11:26:54 -0700 Subject: [PATCH 21/27] Run get_python script when Python fails to load (#4482) Signed-off-by: AMZN-alexpete <26804013+AMZN-alexpete@users.noreply.github.com> --- .../Linux/ProjectManagerDefs_linux.cpp | 1 + .../Platform/Linux/ProjectUtils_linux.cpp | 8 ++ .../Platform/Mac/ProjectManagerDefs_mac.cpp | 1 + .../Platform/Mac/ProjectUtils_mac.cpp | 10 ++ .../Windows/ProjectManagerDefs_windows.cpp | 1 + .../Platform/Windows/ProjectUtils_windows.cpp | 9 ++ .../ProjectManager/Source/Application.cpp | 45 +++++++-- .../Source/ProjectManagerDefs.h | 1 + .../ProjectManager/Source/ProjectUtils.cpp | 96 +++++++++++++++++++ .../ProjectManager/Source/ProjectUtils.h | 24 +++++ .../ProjectManager/Source/PythonBindings.cpp | 7 +- .../ProjectManager/Source/PythonBindings.h | 2 +- .../Source/PythonBindingsInterface.h | 8 ++ 13 files changed, 202 insertions(+), 11 deletions(-) diff --git a/Code/Tools/ProjectManager/Platform/Linux/ProjectManagerDefs_linux.cpp b/Code/Tools/ProjectManager/Platform/Linux/ProjectManagerDefs_linux.cpp index 5ccfbf8eff..f69e0f54ab 100644 --- a/Code/Tools/ProjectManager/Platform/Linux/ProjectManagerDefs_linux.cpp +++ b/Code/Tools/ProjectManager/Platform/Linux/ProjectManagerDefs_linux.cpp @@ -11,5 +11,6 @@ namespace O3DE::ProjectManager { const QString ProjectBuildPathPostfix = ProjectBuildDirectoryName + "/linux"; + const QString GetPythonScriptPath = "python/get_python.sh"; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp b/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp index 7867f6e5fd..0d66009d90 100644 --- a/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp +++ b/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp @@ -86,5 +86,13 @@ namespace O3DE::ProjectManager return AZ::Success(); } + AZ::Outcome RunGetPythonScript(const QString& engineRoot) + { + return ExecuteCommandResultModalDialog( + QString("%1/python/get_python.sh").arg(engineRoot), + {}, + QProcessEnvironment::systemEnvironment(), + QObject::tr("Running get_python script...")); + } } // namespace ProjectUtils } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Platform/Mac/ProjectManagerDefs_mac.cpp b/Code/Tools/ProjectManager/Platform/Mac/ProjectManagerDefs_mac.cpp index 01a7f9e375..f7d3e28bf1 100644 --- a/Code/Tools/ProjectManager/Platform/Mac/ProjectManagerDefs_mac.cpp +++ b/Code/Tools/ProjectManager/Platform/Mac/ProjectManagerDefs_mac.cpp @@ -11,5 +11,6 @@ namespace O3DE::ProjectManager { const QString ProjectBuildPathPostfix = ProjectBuildDirectoryName + "/mac_xcode"; + const QString GetPythonScriptPath = "python/get_python.sh"; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp b/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp index b50039790d..e36f6cd0c8 100644 --- a/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp +++ b/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp @@ -9,6 +9,7 @@ #include #include +#include namespace O3DE::ProjectManager { @@ -94,5 +95,14 @@ namespace O3DE::ProjectManager return AZ::Success(); } + + AZ::Outcome RunGetPythonScript(const QString& engineRoot) + { + return ExecuteCommandResultModalDialog( + QString("%1/python/get_python.sh").arg(engineRoot), + {}, + QProcessEnvironment::systemEnvironment(), + QObject::tr("Running get_python script...")); + } } // namespace ProjectUtils } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Platform/Windows/ProjectManagerDefs_windows.cpp b/Code/Tools/ProjectManager/Platform/Windows/ProjectManagerDefs_windows.cpp index 6bd2194967..6b58458ccd 100644 --- a/Code/Tools/ProjectManager/Platform/Windows/ProjectManagerDefs_windows.cpp +++ b/Code/Tools/ProjectManager/Platform/Windows/ProjectManagerDefs_windows.cpp @@ -10,5 +10,6 @@ namespace O3DE::ProjectManager { const QString ProjectBuildPathPostfix = ProjectBuildDirectoryName + "/windows_vs2019"; + const QString GetPythonScriptPath = "python/get_python.bat"; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp b/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp index 16b80c55e8..831529d5e4 100644 --- a/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp +++ b/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp @@ -130,5 +130,14 @@ namespace O3DE::ProjectManager return AZ::Success(); } + AZ::Outcome RunGetPythonScript(const QString& engineRoot) + { + const QString batPath = QString("%1/python/get_python.bat").arg(engineRoot); + return ExecuteCommandResultModalDialog( + "cmd.exe", + QStringList{"/c", batPath}, + QProcessEnvironment::systemEnvironment(), + QObject::tr("Running get_python script...")); + } } // namespace ProjectUtils } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/Application.cpp b/Code/Tools/ProjectManager/Source/Application.cpp index 9ca107dae5..a7e4805ce9 100644 --- a/Code/Tools/ProjectManager/Source/Application.cpp +++ b/Code/Tools/ProjectManager/Source/Application.cpp @@ -68,17 +68,46 @@ namespace O3DE::ProjectManager } m_pythonBindings = AZStd::make_unique(GetEngineRoot()); - if (!m_pythonBindings || !m_pythonBindings->PythonStarted()) + AZ_Assert(m_pythonBindings, "Failed to create PythonBindings"); + if (!m_pythonBindings->PythonStarted()) { - if (interactive) + if (!interactive) { - QMessageBox::critical(nullptr, QObject::tr("Failed to start Python"), - QObject::tr("This tool requires an O3DE engine with a Python runtime, " - "but either Python is missing or mis-configured. Please rename " - "your python/runtime folder to python/runtime_bak, then run " - "python/get_python.bat to restore the Python runtime folder.")); + return false; + } + + int result = QMessageBox::warning(nullptr, QObject::tr("Failed to start Python"), + QObject::tr("This tool requires an O3DE engine with a Python runtime, " + "but either Python is missing or mis-configured.

Press 'OK' to " + "run the %1 script automatically, or 'Cancel' " + " if you want to manually resolve the issue by renaming your " + " python/runtime folder and running %1 yourself.") + .arg(GetPythonScriptPath), + QMessageBox::Cancel, QMessageBox::Ok); + if (result == QMessageBox::Ok) + { + auto getPythonResult = ProjectUtils::RunGetPythonScript(GetEngineRoot()); + if (!getPythonResult.IsSuccess()) + { + QMessageBox::critical( + nullptr, QObject::tr("Failed to run %1 script").arg(GetPythonScriptPath), + QObject::tr("The %1 script failed, was canceled, or could not be run. " + "Please rename your python/runtime folder and then run " + "
%1
").arg(GetPythonScriptPath)); + } + else if (!m_pythonBindings->StartPython()) + { + QMessageBox::critical( + nullptr, QObject::tr("Failed to start Python"), + QObject::tr("Failed to start Python after running %1") + .arg(GetPythonScriptPath)); + } + } + + if (!m_pythonBindings->PythonStarted()) + { + return false; } - return false; } const AZ::CommandLine* commandLine = GetCommandLine(); diff --git a/Code/Tools/ProjectManager/Source/ProjectManagerDefs.h b/Code/Tools/ProjectManager/Source/ProjectManagerDefs.h index 264515652f..81320e3732 100644 --- a/Code/Tools/ProjectManager/Source/ProjectManagerDefs.h +++ b/Code/Tools/ProjectManager/Source/ProjectManagerDefs.h @@ -18,6 +18,7 @@ namespace O3DE::ProjectManager static const QString ProjectBuildDirectoryName = "build"; extern const QString ProjectBuildPathPostfix; + extern const QString GetPythonScriptPath; static const QString ProjectBuildPathCmakeFiles = "CMakeFiles"; static const QString ProjectBuildErrorLogName = "CMakeProjectBuildError.log"; static const QString ProjectCacheDirectoryName = "Cache"; diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.cpp b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp index e248613d1f..bb2bcd070e 100644 --- a/Code/Tools/ProjectManager/Source/ProjectUtils.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp @@ -23,6 +23,11 @@ #include #include #include +#include +#include +#include +#include +#include #include @@ -512,6 +517,97 @@ namespace O3DE::ProjectManager return ProjectManagerScreen::Invalid; } + AZ::Outcome ExecuteCommandResultModalDialog( + const QString& cmd, + const QStringList& arguments, + const QProcessEnvironment& processEnv, + const QString& title) + { + QString resultOutput; + QProcess execProcess; + execProcess.setProcessEnvironment(processEnv); + execProcess.setProcessChannelMode(QProcess::MergedChannels); + + QProgressDialog dialog(title, QObject::tr("Cancel"), /*minimum=*/0, /*maximum=*/0); + dialog.setMinimumWidth(500); + dialog.setAutoClose(false); + + QProgressBar* bar = new QProgressBar(&dialog); + bar->setTextVisible(false); + bar->setMaximum(0); // infinite + dialog.setBar(bar); + + QLabel* progressLabel = new QLabel(&dialog); + QVBoxLayout* layout = new QVBoxLayout(); + + // pre-fill the field with the title and command + const QString commandOutput = QString("%1
%2 %3
").arg(title).arg(cmd).arg(arguments.join(' ')); + + // replace the label with a scrollable text edit + QTextEdit* detailTextEdit = new QTextEdit(commandOutput, &dialog); + detailTextEdit->setReadOnly(true); + layout->addWidget(detailTextEdit); + layout->setMargin(0); + progressLabel->setLayout(layout); + progressLabel->setMinimumHeight(150); + dialog.setLabel(progressLabel); + + auto readConnection = QObject::connect(&execProcess, &QProcess::readyReadStandardOutput, + [&]() + { + QScrollBar* scrollBar = detailTextEdit->verticalScrollBar(); + bool autoScroll = scrollBar->value() == scrollBar->maximum(); + + QString output = execProcess.readAllStandardOutput(); + detailTextEdit->append(output); + resultOutput.append(output); + + if (autoScroll) + { + scrollBar->setValue(scrollBar->maximum()); + } + }); + + auto exitConnection = QObject::connect(&execProcess, + QOverload::of(&QProcess::finished), + [&](int exitCode, [[maybe_unused]] QProcess::ExitStatus exitStatus) + { + QScrollBar* scrollBar = detailTextEdit->verticalScrollBar(); + dialog.setMaximum(100); + dialog.setValue(dialog.maximum()); + if (exitCode == 0 && scrollBar->value() == scrollBar->maximum()) + { + dialog.close(); + } + else + { + // keep the dialog open so the user can look at the output + dialog.setCancelButtonText(QObject::tr("Continue")); + } + }); + + execProcess.start(cmd, arguments); + + dialog.exec(); + + QObject::disconnect(readConnection); + QObject::disconnect(exitConnection); + + if (execProcess.state() == QProcess::Running) + { + execProcess.kill(); + return AZ::Failure(QObject::tr("Process for command '%1' was canceled").arg(cmd)); + } + + int resultCode = execProcess.exitCode(); + if (resultCode != 0) + { + return AZ::Failure(QObject::tr("Process for command '%1' failed (result code %2").arg(cmd).arg(resultCode)); + } + + return AZ::Success(resultOutput); + } + AZ::Outcome ExecuteCommandResult( const QString& cmd, const QStringList& arguments, diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.h b/Code/Tools/ProjectManager/Source/ProjectUtils.h index 6dd46e3857..1fdf76913e 100644 --- a/Code/Tools/ProjectManager/Source/ProjectUtils.h +++ b/Code/Tools/ProjectManager/Source/ProjectUtils.h @@ -35,15 +35,39 @@ namespace O3DE::ProjectManager ProjectManagerScreen GetProjectManagerScreen(const QString& screen); + /** + * Execute a console command and return the result. + * @param cmd the command + * @param arguments the command argument list + * @param processEnv the environment + * @param commandTimeoutSeconds the amount of time in seconds to let the command run before terminating it + * @return AZ::Outcome with the command result on success + */ AZ::Outcome ExecuteCommandResult( const QString& cmd, const QStringList& arguments, const QProcessEnvironment& processEnv, int commandTimeoutSeconds = ProjectCommandLineTimeoutSeconds); + /** + * Execute a console command, display the progress in a modal dialog and return the result. + * @param cmd the command + * @param arguments the command argument list + * @param processEnv the environment + * @param commandTimeoutSeconds the amount of time in seconds to let the command run before terminating it + * @return AZ::Outcome with the command result on success + */ + AZ::Outcome ExecuteCommandResultModalDialog( + const QString& cmd, + const QStringList& arguments, + const QProcessEnvironment& processEnv, + const QString& title); + AZ::Outcome GetCommandLineProcessEnvironment(); AZ::Outcome GetProjectBuildPath(const QString& projectPath); AZ::Outcome OpenCMakeGUI(const QString& projectPath); + AZ::Outcome RunGetPythonScript(const QString& enginePath); + } // namespace ProjectUtils } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index b9369b5bb0..768e44ce15 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -246,9 +246,11 @@ namespace O3DE::ProjectManager if (Py_IsInitialized()) { AZ_Warning("python", false, "Python is already active"); - return false; + return m_pythonStarted; } + m_pythonStarted = false; + // set PYTHON_HOME AZStd::string pyBasePath = Platform::GetPythonHomePath(PY_PACKAGE, m_enginePath.c_str()); if (!AZ::IO::SystemFile::Exists(pyBasePath.c_str())) @@ -304,7 +306,8 @@ namespace O3DE::ProjectManager // make sure the engine is registered RegisterThisEngine(); - return !PyErr_Occurred(); + m_pythonStarted = !PyErr_Occurred(); + return m_pythonStarted; } catch ([[maybe_unused]] const std::exception& e) { diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.h b/Code/Tools/ProjectManager/Source/PythonBindings.h index 42f04ed6e6..5542fe146e 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.h +++ b/Code/Tools/ProjectManager/Source/PythonBindings.h @@ -31,6 +31,7 @@ namespace O3DE::ProjectManager // PythonBindings overrides bool PythonStarted() override; + bool StartPython() override; // Engine AZ::Outcome GetEngineInfo() override; @@ -70,7 +71,6 @@ namespace O3DE::ProjectManager ProjectInfo ProjectInfoFromPath(pybind11::handle path); ProjectTemplateInfo ProjectTemplateInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath); bool RegisterThisEngine(); - bool StartPython(); bool StopPython(); diff --git a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h index 92139f3df5..589dfb604a 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h +++ b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h @@ -38,6 +38,14 @@ namespace O3DE::ProjectManager */ virtual bool PythonStarted() = 0; + /** + * Attempt to start Python. Normally, Python is started when the bindings are created, + * but this method allows you to attempt to retry starting Python in case the configuration + * has changed. + * @return true if Python was started successfully, false on failure + */ + virtual bool StartPython() = 0; + // Engine /** From bb8971a3addd11eb803cebb1287f9741c2ece612 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Tue, 5 Oct 2021 11:48:27 -0700 Subject: [PATCH 22/27] LYN-5288 | Clicking on a Prefab in the viewport should select the entire Prefab and not an individual Entity (#4462) * Setup work for the ContainerEntity SystemComponent and Interface. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Introduce Container Entity Notification Bus Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Introduce a proxy model to control open/closed state of entity containers. Register prefab containers as entity containers. Profit. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Add open state to OnContainerEntityStatusChanged notification + improvements to comments. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Fix to notification trigger to include new arguments. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Fix issue where the Level container would not be expanded correctly. The Level container is now no longer a container entity (since we don't need to be able to close it). Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Revert the addition of an extra proxy layer (which was causing issues) and just move the container logic to the existing filter. Fix bug in the dataChanged signal. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Fix column count in dataChanged signal to correctly update all column and fix visual glitches. Limit container registration to the prefab WIP flag so that the changes can be submitted with an opt-in mechanism. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Add doubleclick behavior on Outliner items - enters focus mode when double clicking on prefab containers. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * override sourceModel() to store pointer to avoid dynamic casting at every filterAcceptsRow call. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Minor comment fixes and nits Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Move container selection logic to a helper function in the ContainerEntityInterface to simplify reusing it in the near future. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Support lazy initialization for tests (since we do not load a level, the lazy initialization in OnEntityStreamLoadSuccess does not trigger) Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../Application/ToolsApplication.cpp | 2 + .../AzToolsFrameworkModule.cpp | 2 + .../ContainerEntityInterface.h | 61 +++++++++ .../ContainerEntityNotificationBus.h | 41 ++++++ .../ContainerEntitySystemComponent.cpp | 120 ++++++++++++++++++ .../ContainerEntitySystemComponent.h | 54 ++++++++ .../Prefab/PrefabFocusHandler.cpp | 72 ++++++++++- .../Prefab/PrefabFocusHandler.h | 17 ++- .../EditorEntityUiHandlerBase.cpp | 46 +++++-- .../EditorEntityUiHandlerBase.h | 3 + .../UI/Outliner/EntityOutlinerListModel.cpp | 25 +++- .../UI/Outliner/EntityOutlinerListModel.hxx | 5 + .../EntityOutlinerSortFilterProxyModel.cpp | 22 ++++ .../EntityOutlinerSortFilterProxyModel.hxx | 12 +- .../UI/Outliner/EntityOutlinerWidget.cpp | 9 +- .../UI/Outliner/EntityOutlinerWidget.hxx | 2 + .../UI/Prefab/PrefabIntegrationManager.cpp | 32 ++++- .../UI/Prefab/PrefabIntegrationManager.h | 3 + .../UI/Prefab/PrefabUiHandler.cpp | 15 +++ .../UI/Prefab/PrefabUiHandler.h | 3 +- .../ViewportSelection/EditorHelpers.cpp | 11 +- .../aztoolsframework_files.cmake | 4 + 22 files changed, 531 insertions(+), 30 deletions(-) create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityInterface.h create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityNotificationBus.h create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.h diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp index 717e0c6f8a..c54735fe91 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -251,6 +252,7 @@ namespace AzToolsFramework azrtti_typeid(), azrtti_typeid(), azrtti_typeid(), + azrtti_typeid(), azrtti_typeid(), azrtti_typeid(), azrtti_typeid(), diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFrameworkModule.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFrameworkModule.cpp index b68d086892..05d67d9d71 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFrameworkModule.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFrameworkModule.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -70,6 +71,7 @@ namespace AzToolsFramework Components::EditorSelectionAccentSystemComponent::CreateDescriptor(), EditorEntityContextComponent::CreateDescriptor(), EditorEntityFixupComponent::CreateDescriptor(), + ContainerEntitySystemComponent::CreateDescriptor(), FocusModeSystemComponent::CreateDescriptor(), SliceMetadataEntityContextComponent::CreateDescriptor(), SliceRequestComponent::CreateDescriptor(), diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityInterface.h new file mode 100644 index 0000000000..45da3a9d8f --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityInterface.h @@ -0,0 +1,61 @@ +/* + * 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 +{ + //! Outcome object that returns an error message in case of failure to allow caller to handle internal errors. + using ContainerEntityOperationResult = AZ::Outcome; + + //! ContainerEntityInterface + //! An entity registered as Container is just like a regular entity when open. If its state is changed + //! to closed, all descendants of the entity will be treated as part of the entity itself. Selecting any + //! descendant will result in the container being selected, and descendants will be hidden until the + //! container is opened. + class ContainerEntityInterface + { + public: + AZ_RTTI(ContainerEntityInterface, "{0A877C3A-726C-4FD2-BAFE-A2B9F1DE78E4}"); + + //! Registers the entity as a container. The container will be closed by default. + //! @param entityId The entityId that will be registered as a container. + virtual ContainerEntityOperationResult RegisterEntityAsContainer(AZ::EntityId entityId) = 0; + + //! Unregisters the entity as a container. + //! The system will retain the closed state in case the entity is registered again later, but + //! if queried the entity will no longer behave as a container. + //! @param entityId The entityId that will be unregistered as a container. + virtual ContainerEntityOperationResult UnregisterEntityAsContainer(AZ::EntityId entityId) = 0; + + //! Returns whether the entity id provided is registered as a container. + virtual bool IsContainer(AZ::EntityId entityId) const = 0; + + //! Sets the open state of the container entity provided. + //! @param entityId The entityId whose open state will be set. + //! @param open True if the container should be opened, false if it should be closed. + //! @return An error message if the operation was invalid, success otherwise. + virtual ContainerEntityOperationResult SetContainerOpenState(AZ::EntityId entityId, bool open) = 0; + + //! If the entity id provided is registered as a container, it returns whether it's open. + //! @note the default value for non-containers is true, so this function can be called without + //! verifying whether the entityId is registered as a container beforehand, since the container's + //! open behavior is exactly the same as the one of a regular entity. + //! @return False if the entityId is registered as a container, and its state is closed. True otherwise. + virtual bool IsContainerOpen(AZ::EntityId entityId) const = 0; + + //! Detects if one of the ancestors of entityId is a closed container entity. + //! @return The highest closed entity container id if any, or entityId otherwise. + virtual AZ::EntityId FindHighestSelectableEntity(AZ::EntityId entityId) const = 0; + + }; + +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityNotificationBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityNotificationBus.h new file mode 100644 index 0000000000..95608feefb --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityNotificationBus.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include + +#include + +namespace AzToolsFramework +{ + //! Used to notify changes of state for Container Entities. + class ContainerEntityNotifications + : public AZ::EBusTraits + { + public: + ////////////////////////////////////////////////////////////////////////// + // EBusTraits overrides + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; + using BusIdType = AzFramework::EntityContextId; + ////////////////////////////////////////////////////////////////////////// + + //! Triggered when a container entity status changes. + //! @param entityId The entity whose status has changed. + //! @param open The open state the container was changed to. + virtual void OnContainerEntityStatusChanged([[maybe_unused]] AZ::EntityId entityId, [[maybe_unused]] bool open) {} + + protected: + ~ContainerEntityNotifications() = default; + }; + + using ContainerEntityNotificationBus = AZ::EBus; + +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp new file mode 100644 index 0000000000..0ea2eeb5f6 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp @@ -0,0 +1,120 @@ +/* + * 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 +{ + void ContainerEntitySystemComponent::Activate() + { + AZ::Interface::Register(this); + } + + void ContainerEntitySystemComponent::Deactivate() + { + AZ::Interface::Unregister(this); + } + + void ContainerEntitySystemComponent::Reflect([[maybe_unused]] AZ::ReflectContext* context) + { + } + + void ContainerEntitySystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) + { + provided.push_back(AZ_CRC_CE("ContainerEntityService")); + } + + ContainerEntityOperationResult ContainerEntitySystemComponent::RegisterEntityAsContainer(AZ::EntityId entityId) + { + if (IsContainer(entityId)) + { + return AZ::Failure(AZStd::string( + "ContainerEntitySystemComponent error - trying to register entity as container twice.")); + } + + m_containers.insert(entityId); + + return AZ::Success(); + } + + ContainerEntityOperationResult ContainerEntitySystemComponent::UnregisterEntityAsContainer(AZ::EntityId entityId) + { + if (!IsContainer(entityId)) + { + return AZ::Failure(AZStd::string( + "ContainerEntitySystemComponent error - trying to unregister entity that is not a container.")); + } + + m_containers.erase(entityId); + + return AZ::Success(); + } + + bool ContainerEntitySystemComponent::IsContainer(AZ::EntityId entityId) const + { + return m_containers.contains(entityId); + } + + ContainerEntityOperationResult ContainerEntitySystemComponent::SetContainerOpenState(AZ::EntityId entityId, bool open) + { + if (!IsContainer(entityId)) + { + return AZ::Failure(AZStd::string( + "ContainerEntitySystemComponent error - cannot set open state of entity that was not registered as container.")); + } + + if(open) + { + m_openContainers.insert(entityId); + } + else + { + m_openContainers.erase(entityId); + } + + ContainerEntityNotificationBus::Broadcast(&ContainerEntityNotificationBus::Events::OnContainerEntityStatusChanged, entityId, open); + + return AZ::Success(); + } + + bool ContainerEntitySystemComponent::IsContainerOpen(AZ::EntityId entityId) const + { + // If the entity is not a container, it should behave as open. + if(!m_containers.contains(entityId)) + { + return true; + } + + // If the entity is a container, return its state. + return m_openContainers.contains(entityId); + } + + AZ::EntityId ContainerEntitySystemComponent::FindHighestSelectableEntity(AZ::EntityId entityId) const + { + AZ::EntityId highestSelectableEntityId = entityId; + + // Go up the hierarchy until you hit the root + while (entityId.IsValid()) + { + if (!IsContainerOpen(entityId)) + { + // If one of the ancestors is a container and it's closed, keep track of its id. + // We only return of the higher closed container in the hierarchy. + highestSelectableEntityId = entityId; + } + + AZ::TransformBus::EventResult(entityId, entityId, &AZ::TransformBus::Events::GetParentId); + } + + return highestSelectableEntityId; + } + +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.h new file mode 100644 index 0000000000..18c0fb70c6 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include + +#include + +namespace AzToolsFramework +{ + //! System Component to track Container Entity registration and open state. + //! An entity registered as Container is just like a regular entity when open. If its state is changed + //! to closed, all descendants of the entity will be treated as part of the entity itself. Selecting any + //! descendant will result in the container being selected, and descendants will be hidden until the + //! container is opened. + class ContainerEntitySystemComponent final + : public AZ::Component + , private ContainerEntityInterface + { + public: + AZ_COMPONENT(ContainerEntitySystemComponent, "{74349759-B36B-44A6-B89F-F45D7111DD11}"); + + ContainerEntitySystemComponent() = default; + virtual ~ContainerEntitySystemComponent() = default; + + // AZ::Component overrides ... + void Activate() override; + void Deactivate() override; + + static void Reflect(AZ::ReflectContext* context); + + static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); + + // ContainerEntityInterface overrides ... + ContainerEntityOperationResult RegisterEntityAsContainer(AZ::EntityId entityId) override; + ContainerEntityOperationResult UnregisterEntityAsContainer(AZ::EntityId entityId) override; + bool IsContainer(AZ::EntityId entityId) const override; + ContainerEntityOperationResult SetContainerOpenState(AZ::EntityId entityId, bool open) override; + bool IsContainerOpen(AZ::EntityId entityId) const override; + AZ::EntityId FindHighestSelectableEntity(AZ::EntityId entityId) const override; + + private: + AZStd::unordered_set m_containers; //!< All entities in this set are containers. + AZStd::unordered_set m_openContainers; //!< All entities in this set are open containers. + }; + +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp index 4e58bbdf05..9ffc18af5a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp @@ -8,6 +8,7 @@ #include +#include #include #include #include @@ -35,6 +36,30 @@ namespace AzToolsFramework::Prefab EditorEntityContextNotificationBus::Handler::BusDisconnect(); } + void PrefabFocusHandler::Initialize() + { + m_containerEntityInterface = AZ::Interface::Get(); + AZ_Assert( + m_containerEntityInterface, + "Prefab - PrefabFocusHandler - " + "Container Entity Interface could not be found. " + "Check that it is being correctly initialized."); + + m_focusModeInterface = AZ::Interface::Get(); + AZ_Assert( + m_focusModeInterface, + "Prefab - PrefabFocusHandler - " + "Focus Mode Interface could not be found. " + "Check that it is being correctly initialized."); + + m_instanceEntityMapperInterface = AZ::Interface::Get(); + AZ_Assert( + m_instanceEntityMapperInterface, + "Prefab - PrefabFocusHandler - " + "Instance Entity Mapper Interface could not be found. " + "Check that it is being correctly initialized."); + } + PrefabFocusOperationResult PrefabFocusHandler::FocusOnOwningPrefab(AZ::EntityId entityId) { InstanceOptionalReference focusedInstance; @@ -44,7 +69,7 @@ namespace AzToolsFramework::Prefab PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface = AZ::Interface::Get(); - if(!prefabEditorEntityOwnershipInterface) + if (!prefabEditorEntityOwnershipInterface) { return AZ::Failure(AZStd::string("Could not focus on root prefab instance - internal error " "(PrefabEditorEntityOwnershipInterface unavailable).")); @@ -79,8 +104,16 @@ namespace AzToolsFramework::Prefab return AZ::Failure(AZStd::string("Prefab Focus Handler: invalid instance to focus on.")); } + if (!m_isInitialized) + { + Initialize(); + } + if (!m_focusedInstance.has_value() || &m_focusedInstance->get() != &focusedInstance->get()) { + // Close all container entities in the old path + CloseInstanceContainers(m_instanceFocusVector); + m_focusedInstance = focusedInstance; m_focusedTemplateId = focusedInstance->get().GetTemplateId(); @@ -103,12 +136,14 @@ namespace AzToolsFramework::Prefab } // Focus on the descendants of the container entity - if (FocusModeInterface* focusModeInterface = AZ::Interface::Get()) - { - focusModeInterface->SetFocusRoot(containerEntityId); - } + m_focusModeInterface->SetFocusRoot(containerEntityId); + // Refresh path variables RefreshInstanceFocusList(); + + // Open all container entities in the new path + OpenInstanceContainers(m_instanceFocusVector); + PrefabFocusNotificationBus::Broadcast(&PrefabFocusNotifications::OnPrefabFocusChanged); } @@ -156,6 +191,11 @@ namespace AzToolsFramework::Prefab void PrefabFocusHandler::OnEntityStreamLoadSuccess() { + if (!m_isInitialized) + { + Initialize(); + } + // Focus on the root prefab (AZ::EntityId() will default to it) FocusOnOwningPrefab(AZ::EntityId()); } @@ -184,4 +224,26 @@ namespace AzToolsFramework::Prefab } } + void PrefabFocusHandler::OpenInstanceContainers(const AZStd::vector& instances) const + { + for (const InstanceOptionalReference& instance : instances) + { + if (instance.has_value()) + { + m_containerEntityInterface->SetContainerOpenState(instance->get().GetContainerEntityId(), true); + } + } + } + + void PrefabFocusHandler::CloseInstanceContainers(const AZStd::vector& instances) const + { + for (const InstanceOptionalReference& instance : instances) + { + if (instance.has_value()) + { + m_containerEntityInterface->SetContainerOpenState(instance->get().GetContainerEntityId(), false); + } + } + } + } // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h index 2ccec36882..2f631f772d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h @@ -15,6 +15,12 @@ #include #include +namespace AzToolsFramework +{ + class ContainerEntityInterface; + class FocusModeInterface; +} + namespace AzToolsFramework::Prefab { class InstanceEntityMapperInterface; @@ -30,6 +36,8 @@ namespace AzToolsFramework::Prefab PrefabFocusHandler(); ~PrefabFocusHandler(); + void Initialize(); + // PrefabFocusInterface overrides ... PrefabFocusOperationResult FocusOnOwningPrefab(AZ::EntityId entityId) override; PrefabFocusOperationResult FocusOnPathIndex(AzFramework::EntityContextId entityContextId, int index) override; @@ -46,12 +54,19 @@ namespace AzToolsFramework::Prefab PrefabFocusOperationResult FocusOnPrefabInstance(InstanceOptionalReference focusedInstance); void RefreshInstanceFocusList(); + void OpenInstanceContainers(const AZStd::vector& instances) const; + void CloseInstanceContainers(const AZStd::vector& instances) const; + InstanceOptionalReference m_focusedInstance; TemplateId m_focusedTemplateId; AZStd::vector m_instanceFocusVector; AZ::IO::Path m_instanceFocusPath; - InstanceEntityMapperInterface* m_instanceEntityMapperInterface; + ContainerEntityInterface* m_containerEntityInterface = nullptr; + FocusModeInterface* m_focusModeInterface = nullptr; + InstanceEntityMapperInterface* m_instanceEntityMapperInterface = nullptr; + + bool m_isInitialized = false; }; } // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/EditorEntityUi/EditorEntityUiHandlerBase.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/EditorEntityUi/EditorEntityUiHandlerBase.cpp index a0da20ebf0..3cdcade1b0 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/EditorEntityUi/EditorEntityUiHandlerBase.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/EditorEntityUi/EditorEntityUiHandlerBase.cpp @@ -37,51 +37,71 @@ namespace AzToolsFramework return m_handlerId; } - QString EditorEntityUiHandlerBase::GenerateItemInfoString(AZ::EntityId /*entityId*/) const + QString EditorEntityUiHandlerBase::GenerateItemInfoString([[maybe_unused]] AZ::EntityId entityId) const { return QString(); } - QString EditorEntityUiHandlerBase::GenerateItemTooltip(AZ::EntityId /*entityId*/) const + QString EditorEntityUiHandlerBase::GenerateItemTooltip([[maybe_unused]] AZ::EntityId entityId) const { return QString(); } - QIcon EditorEntityUiHandlerBase::GenerateItemIcon(AZ::EntityId /*entityId*/) const + QIcon EditorEntityUiHandlerBase::GenerateItemIcon([[maybe_unused]] AZ::EntityId entityId) const { return QIcon(); } - bool EditorEntityUiHandlerBase::CanToggleLockVisibility(AZ::EntityId /*entityId*/) const + bool EditorEntityUiHandlerBase::CanToggleLockVisibility([[maybe_unused]] AZ::EntityId entityId) const { return true; } - bool EditorEntityUiHandlerBase::CanRename(AZ::EntityId /*entityId*/) const + bool EditorEntityUiHandlerBase::CanRename([[maybe_unused]] AZ::EntityId entityId) const { return true; } - void EditorEntityUiHandlerBase::PaintItemBackground(QPainter* /*painter*/, const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/) const + void EditorEntityUiHandlerBase::PaintItemBackground( + [[maybe_unused]] QPainter* painter, + [[maybe_unused]] const QStyleOptionViewItem& option, + [[maybe_unused]] const QModelIndex& index) const { } - void EditorEntityUiHandlerBase::PaintDescendantBackground(QPainter* /*painter*/, const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/, - const QModelIndex& /*descendantIndex*/) const + void EditorEntityUiHandlerBase::PaintDescendantBackground( + [[maybe_unused]] QPainter* painter, + [[maybe_unused]] const QStyleOptionViewItem& option, + [[maybe_unused]] const QModelIndex& index, + [[maybe_unused]] const QModelIndex& descendantIndex) const { } - void EditorEntityUiHandlerBase::PaintDescendantBranchBackground(QPainter* /*painter*/, const QTreeView* /*view*/, const QRect& /*rect*/, - const QModelIndex& /*index*/, const QModelIndex& /*descendantIndex*/) const + void EditorEntityUiHandlerBase::PaintDescendantBranchBackground( + [[maybe_unused]] QPainter* painter, + [[maybe_unused]] const QTreeView* view, + [[maybe_unused]] const QRect& rect, + [[maybe_unused]] const QModelIndex& index, + [[maybe_unused]] const QModelIndex& descendantIndex) const { } - void EditorEntityUiHandlerBase::PaintItemForeground(QPainter* /*painter*/, const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/) const + void EditorEntityUiHandlerBase::PaintItemForeground( + [[maybe_unused]] QPainter* painter, + [[maybe_unused]] const QStyleOptionViewItem& option, + [[maybe_unused]] const QModelIndex& index) const { } - void EditorEntityUiHandlerBase::PaintDescendantForeground(QPainter* /*painter*/, const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/, - const QModelIndex& /*descendantIndex*/) const + void EditorEntityUiHandlerBase::PaintDescendantForeground( + [[maybe_unused]] QPainter* painter, + [[maybe_unused]] const QStyleOptionViewItem& option, + [[maybe_unused]] const QModelIndex& index, + [[maybe_unused]] const QModelIndex& descendantIndex) const + { + } + + void EditorEntityUiHandlerBase::OnDoubleClick([[maybe_unused]] AZ::EntityId entityId) const { } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/EditorEntityUi/EditorEntityUiHandlerBase.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/EditorEntityUi/EditorEntityUiHandlerBase.h index c37b099272..9554ad01fc 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/EditorEntityUi/EditorEntityUiHandlerBase.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/EditorEntityUi/EditorEntityUiHandlerBase.h @@ -61,6 +61,9 @@ namespace AzToolsFramework virtual void PaintDescendantForeground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index, const QModelIndex& descendantIndex) const; + //! Triggered when the entity is double clicked in the Outliner. + virtual void OnDoubleClick(AZ::EntityId entityId) const; + private: EditorEntityUiHandlerId m_handlerId = 0; }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp index 2872c1bce3..234696ff2a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp @@ -88,6 +88,7 @@ namespace AzToolsFramework EntityOutlinerListModel::~EntityOutlinerListModel() { + ContainerEntityNotificationBus::Handler::BusDisconnect(); EditorEntityInfoNotificationBus::Handler::BusDisconnect(); EditorEntityContextNotificationBus::Handler::BusDisconnect(); ToolsApplicationEvents::Bus::Handler::BusDisconnect(); @@ -105,6 +106,12 @@ namespace AzToolsFramework EntityCompositionNotificationBus::Handler::BusConnect(); AZ::EntitySystemBus::Handler::BusConnect(); + AzFramework::EntityContextId editorEntityContextId = AzFramework::EntityContextId::CreateNull(); + AzToolsFramework::EditorEntityContextRequestBus::BroadcastResult( + editorEntityContextId, &AzToolsFramework::EditorEntityContextRequestBus::Events::GetEditorEntityContextId); + + ContainerEntityNotificationBus::Handler::BusConnect(editorEntityContextId); + m_editorEntityUiInterface = AZ::Interface::Get(); AZ_Assert(m_editorEntityUiInterface != nullptr, "EntityOutlinerListModel requires a EditorEntityUiInterface instance on Initialize."); @@ -1333,12 +1340,26 @@ namespace AzToolsFramework emit EnableSelectionUpdates(true); } - void EntityOutlinerListModel::OnEntityRuntimeActivationChanged(AZ::EntityId entityId, bool activeOnStart) + void EntityOutlinerListModel::OnEntityRuntimeActivationChanged(AZ::EntityId entityId, [[maybe_unused]] bool activeOnStart) { - AZ_UNUSED(activeOnStart); QueueEntityUpdate(entityId); } + void EntityOutlinerListModel::OnContainerEntityStatusChanged(AZ::EntityId entityId, [[maybe_unused]] bool open) + { + QModelIndex changedIndex = GetIndexFromEntity(entityId); + + // Trigger a refresh of all direct children so that they can be shown or hidden appropriately. + int numChildren = rowCount(changedIndex); + if (numChildren > 0) + { + emit dataChanged(index(0, 0, changedIndex), index(numChildren - 1, ColumnCount - 1, changedIndex)); + } + + // Always expand containers + QueueEntityToExpand(entityId, true); + } + void EntityOutlinerListModel::OnEntityInfoUpdatedRemoveChildBegin([[maybe_unused]] AZ::EntityId parentId, [[maybe_unused]] AZ::EntityId childId) { //add/remove operations trigger selection change signals which assert and break undo/redo operations in progress in inspector etc. diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx index 4b13aa6d27..7b946c6304 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -54,6 +55,7 @@ namespace AzToolsFramework , private EntityCompositionNotificationBus::Handler , private EditorEntityRuntimeActivationChangeNotificationBus::Handler , private AZ::EntitySystemBus::Handler + , private ContainerEntityNotificationBus::Handler { Q_OBJECT; @@ -216,6 +218,9 @@ namespace AzToolsFramework // EditorEntityRuntimeActivationChangeNotificationBus::Handler void OnEntityRuntimeActivationChanged(AZ::EntityId entityId, bool activeOnStart) override; + // ContainerEntityNotificationBus overrides ... + void OnContainerEntityStatusChanged(AZ::EntityId entityId, bool open) override; + // Drag/Drop of components from Component Palette. bool dropMimeDataComponentPalette(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSortFilterProxyModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSortFilterProxyModel.cpp index 841a01f5e5..600ca284f4 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSortFilterProxyModel.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSortFilterProxyModel.cpp @@ -11,6 +11,8 @@ #include #include +#include + #include "EntityOutlinerListModel.hxx" namespace AzToolsFramework @@ -19,6 +21,10 @@ namespace AzToolsFramework EntityOutlinerSortFilterProxyModel::EntityOutlinerSortFilterProxyModel(QObject* pParent) : QSortFilterProxyModel(pParent) { + m_containerEntityInterface = AZ::Interface::Get(); + AZ_Assert( + m_containerEntityInterface != nullptr, + "EntityOutlinerContainerProxyModel requires a ContainerEntityInterface instance on construction."); } void EntityOutlinerSortFilterProxyModel::UpdateFilter() @@ -26,8 +32,24 @@ namespace AzToolsFramework invalidateFilter(); } + void EntityOutlinerSortFilterProxyModel::setSourceModel(QAbstractItemModel* sourceModel) + { + QSortFilterProxyModel::setSourceModel(sourceModel); + + m_listModel = qobject_cast(sourceModel); + AZ_Assert(m_listModel != nullptr, "EntityOutlinerContainerProxyModel requires an EntityOutlinerListModel as its source ."); + } + bool EntityOutlinerSortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const { + // Retrieve the entityId of the parent entity + AZ::EntityId parentEntityId = m_listModel->GetEntityFromIndex(sourceParent); + + if(!m_containerEntityInterface->IsContainerOpen(parentEntityId)) + { + return false; + } + QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); QVariant visibilityData = sourceModel()->data(index, EntityOutlinerListModel::VisibilityRole); return visibilityData.isValid() ? visibilityData.toBool() : true; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSortFilterProxyModel.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSortFilterProxyModel.hxx index b7e1a3f869..c6e1410688 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSortFilterProxyModel.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSortFilterProxyModel.hxx @@ -19,11 +19,12 @@ namespace AzToolsFramework { + class ContainerEntityInterface; + class EntityOutlinerListModel; - /*! - * Enables the Outliner to filter entries based on search string. - * Enables the Outliner to do custom sorting on entries. - */ + //! Enables the Outliner to filter entries based on search string. + //! Enables the Outliner to do custom sorting on entries. + //! Enforces the correct rendering for container entities. class EntityOutlinerSortFilterProxyModel : public QSortFilterProxyModel { @@ -37,12 +38,15 @@ namespace AzToolsFramework void UpdateFilter(); // Qt overrides + void setSourceModel(QAbstractItemModel* sourceModel) override; bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override; bool lessThan(const QModelIndex& left, const QModelIndex& right) const override; void sort(int column, Qt::SortOrder order) override; private: QString m_filterName; + EntityOutlinerListModel* m_listModel = nullptr; + ContainerEntityInterface* m_containerEntityInterface = nullptr; }; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp index 689e5b5dc4..8f90d2c0d7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp @@ -198,6 +198,7 @@ namespace AzToolsFramework m_proxyModel = aznew EntityOutlinerSortFilterProxyModel(this); m_proxyModel->setSourceModel(m_listModel); + m_gui->m_objectTree->setModel(m_proxyModel); // Link up signals for informing the model of tree changes using the proxy as an intermediary @@ -905,8 +906,12 @@ namespace AzToolsFramework } } - void EntityOutlinerWidget::OnTreeItemDoubleClicked(const QModelIndex& /*index*/) + void EntityOutlinerWidget::OnTreeItemDoubleClicked(const QModelIndex& index) { + if (AZ::EntityId entityId = GetEntityIdFromIndex(index); auto entityUiHandler = m_editorEntityUiInterface->GetHandler(entityId)) + { + entityUiHandler->OnDoubleClick(entityId); + } } void EntityOutlinerWidget::OnTreeItemExpanded(const QModelIndex& index) @@ -1142,7 +1147,7 @@ namespace AzToolsFramework { QTimer::singleShot(1, this, [this]() { m_gui->m_objectTree->setUpdatesEnabled(true); - m_gui->m_objectTree->expand(m_proxyModel->index(0,0)); + m_gui->m_objectTree->expandToDepth(0); }); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.hxx index 78aced3587..78927359f2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.hxx @@ -41,6 +41,7 @@ namespace AzToolsFramework { class EditorEntityUiInterface; class EntityOutlinerListModel; + class EntityOutlinerContainerProxyModel; class EntityOutlinerSortFilterProxyModel; namespace EntityOutliner @@ -117,6 +118,7 @@ namespace AzToolsFramework Ui::EntityOutlinerWidgetUI* m_gui; EntityOutlinerListModel* m_listModel; + EntityOutlinerContainerProxyModel* m_containerModel; EntityOutlinerSortFilterProxyModel* m_proxyModel; AZ::u64 m_selectionContextId; AZStd::vector m_selectedEntityIds; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp index 34152f8287..62842e18d5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -56,7 +57,7 @@ namespace AzToolsFramework { namespace Prefab { - + ContainerEntityInterface* PrefabIntegrationManager::s_containerEntityInterface = nullptr; EditorEntityUiInterface* PrefabIntegrationManager::s_editorEntityUiInterface = nullptr; PrefabFocusInterface* PrefabIntegrationManager::s_prefabFocusInterface = nullptr; PrefabLoaderInterface* PrefabIntegrationManager::s_prefabLoaderInterface = nullptr; @@ -89,6 +90,13 @@ namespace AzToolsFramework PrefabIntegrationManager::PrefabIntegrationManager() { + s_containerEntityInterface = AZ::Interface::Get(); + if (s_containerEntityInterface == nullptr) + { + AZ_Assert(false, "Prefab - could not get ContainerEntityInterface on PrefabIntegrationManager construction."); + return; + } + s_editorEntityUiInterface = AZ::Interface::Get(); if (s_editorEntityUiInterface == nullptr) { @@ -1057,6 +1065,7 @@ namespace AzToolsFramework void PrefabIntegrationManager::OnPrefabComponentActivate(AZ::EntityId entityId) { + // Register entity to appropriate UI Handler for UI overrides if (s_prefabPublicInterface->IsLevelInstanceContainerEntity(entityId)) { s_editorEntityUiInterface->RegisterEntity(entityId, m_levelRootUiHandler.GetHandlerId()); @@ -1064,11 +1073,32 @@ namespace AzToolsFramework else { s_editorEntityUiInterface->RegisterEntity(entityId, m_prefabUiHandler.GetHandlerId()); + + bool prefabWipFeaturesEnabled = false; + AzFramework::ApplicationRequests::Bus::BroadcastResult( + prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled); + + if (prefabWipFeaturesEnabled) + { + // Register entity as a container + s_containerEntityInterface->RegisterEntityAsContainer(entityId); + } } } void PrefabIntegrationManager::OnPrefabComponentDeactivate(AZ::EntityId entityId) { + bool prefabWipFeaturesEnabled = false; + AzFramework::ApplicationRequests::Bus::BroadcastResult( + prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled); + + if (prefabWipFeaturesEnabled && !s_prefabPublicInterface->IsLevelInstanceContainerEntity(entityId)) + { + // Unregister entity as a container + s_containerEntityInterface->UnregisterEntityAsContainer(entityId); + } + + // Unregister entity from UI Handler s_editorEntityUiInterface->UnregisterEntity(entityId); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h index 6f66b1f514..44e30b2013 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h @@ -26,6 +26,8 @@ namespace AzToolsFramework { + class ContainerEntityInterface; + namespace Prefab { class PrefabFocusInterface; @@ -134,6 +136,7 @@ namespace AzToolsFramework static const AZStd::string s_prefabFileExtension; + static ContainerEntityInterface* s_containerEntityInterface; static EditorEntityUiInterface* s_editorEntityUiInterface; static PrefabFocusInterface* s_prefabFocusInterface; static PrefabLoaderInterface* s_prefabLoaderInterface; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.cpp index c802850c4b..7d1f3485aa 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.cpp @@ -8,6 +8,8 @@ #include +#include + #include #include #include @@ -317,4 +319,17 @@ namespace AzToolsFramework return Internal_GetLastVisibleChild(model, lastChild); } + + void PrefabUiHandler::OnDoubleClick(AZ::EntityId entityId) const + { + bool prefabWipFeaturesEnabled = false; + AzFramework::ApplicationRequests::Bus::BroadcastResult( + prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled); + + if (prefabWipFeaturesEnabled) + { + // Focus on this prefab + m_prefabFocusInterface->FocusOnOwningPrefab(entityId); + } + } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.h index 547c100eb1..bb7168f409 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabUiHandler.h @@ -29,13 +29,14 @@ namespace AzToolsFramework PrefabUiHandler(); ~PrefabUiHandler() override = default; - // EditorEntityUiHandler... + // EditorEntityUiHandler overrides ... QString GenerateItemInfoString(AZ::EntityId entityId) const override; QString GenerateItemTooltip(AZ::EntityId entityId) const override; QIcon GenerateItemIcon(AZ::EntityId entityId) const override; void PaintItemBackground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override; void PaintDescendantBackground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index, const QModelIndex& descendantIndex) const override; + void OnDoubleClick(AZ::EntityId entityId) const override; private: Prefab::PrefabFocusInterface* m_prefabFocusInterface = nullptr; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp index 57e6c9ff7a..3ce350287f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp @@ -13,8 +13,9 @@ #include #include #include -#include #include +#include +#include #include #include #include @@ -191,6 +192,14 @@ namespace AzToolsFramework return AZ::EntityId(); } + // Container Entity support - if the entity that is being selected is part of a closed container, + // change the selection to the container instead. + ContainerEntityInterface* containerEntityInterface = AZ::Interface::Get(); + if (containerEntityInterface) + { + return containerEntityInterface->FindHighestSelectableEntity(entityIdUnderCursor); + } + return entityIdUnderCursor; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index f09d4f9b72..0866b225c1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -114,6 +114,10 @@ set(FILES Component/EditorLevelComponentAPIBus.h Component/EditorLevelComponentAPIComponent.cpp Component/EditorLevelComponentAPIComponent.h + ContainerEntity/ContainerEntityInterface.h + ContainerEntity/ContainerEntityNotificationBus.h + ContainerEntity/ContainerEntitySystemComponent.cpp + ContainerEntity/ContainerEntitySystemComponent.h Editor/EditorContextMenuBus.h Editor/EditorSettingsAPIBus.h Entity/EditorEntityStartStatus.h From 643bd84739048fd18785dbfb881d01ba23655e90 Mon Sep 17 00:00:00 2001 From: galibzon <66021303+galibzon@users.noreply.github.com> Date: Tue, 5 Oct 2021 14:21:21 -0500 Subject: [PATCH 23/27] Create helper function for getting threads per (#4480) * Create helper function for getting threads per group from a compute shader Added GetComputeShaderNumThreads() functions to RPIUtils. By default the function returns 1, 1, 1 in case of errors. Updated existing code that was looking for 'numthreads' attribute data with the new GetComputeShaderNumThreads() API. Signed-off-by: garrieta --- .../DiffuseProbeGridBlendDistancePass.cpp | 23 +----- .../DiffuseProbeGridBlendIrradiancePass.cpp | 23 +----- .../DiffuseProbeGridBorderUpdatePass.cpp | 23 +----- .../DiffuseProbeGridClassificationPass.cpp | 23 +----- .../DiffuseProbeGridRelocationPass.cpp | 23 +----- .../MorphTargets/MorphTargetDispatchItem.cpp | 11 +-- .../SkinnedMesh/SkinnedMeshDispatchItem.cpp | 18 ++--- .../Code/Include/Atom/RPI.Public/RPIUtils.h | 18 +++++ .../Source/RPI.Public/Pass/ComputePass.cpp | 27 ++----- .../RPI/Code/Source/RPI.Public/RPIUtils.cpp | 74 +++++++++++++++++++ 10 files changed, 124 insertions(+), 139 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp index 69a4ecdee5..cf1897054a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp @@ -54,27 +54,10 @@ namespace AZ m_srgLayout = m_shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Pass); // retrieve the number of threads per thread group from the shader - const auto numThreads = m_shader->GetAsset()->GetAttribute(RHI::ShaderStage::Compute, Name{ "numthreads" }); - if (numThreads) + const auto outcome = RPI::GetComputeShaderNumThreads(m_shader->GetAsset(), m_dispatchArgs); + if (!outcome.IsSuccess()) { - const RHI::ShaderStageAttributeArguments& args = *numThreads; - bool validArgs = args.size() == 3; - if (validArgs) - { - validArgs &= args[0].type() == azrtti_typeid(); - validArgs &= args[1].type() == azrtti_typeid(); - validArgs &= args[2].type() == azrtti_typeid(); - } - - if (!validArgs) - { - AZ_Error("PassSystem", false, "[DiffuseProbeGridBlendDistancePass '%s']: Shader '%s' contains invalid numthreads arguments.", GetPathName().GetCStr(), shaderFilePath.c_str()); - return; - } - - m_dispatchArgs.m_threadsPerGroupX = static_cast(AZStd::any_cast(args[0])); - m_dispatchArgs.m_threadsPerGroupY = static_cast(AZStd::any_cast(args[1])); - m_dispatchArgs.m_threadsPerGroupZ = static_cast(AZStd::any_cast(args[2])); + AZ_Error("PassSystem", false, "[DiffuseProbeGridBlendDistancePass '%s']: Shader '%s' contains invalid numthreads arguments:\n%s", GetPathName().GetCStr(), shaderFilePath.c_str(), outcome.GetError().c_str()); } } diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp index 83ef312bf4..f4733c833a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp @@ -54,27 +54,10 @@ namespace AZ m_srgLayout = m_shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Pass); // retrieve the number of threads per thread group from the shader - const auto numThreads = m_shader->GetAsset()->GetAttribute(RHI::ShaderStage::Compute, Name{ "numthreads" }); - if (numThreads) + const auto outcome = RPI::GetComputeShaderNumThreads(m_shader->GetAsset(), m_dispatchArgs); + if (!outcome.IsSuccess()) { - const RHI::ShaderStageAttributeArguments& args = *numThreads; - bool validArgs = args.size() == 3; - if (validArgs) - { - validArgs &= args[0].type() == azrtti_typeid(); - validArgs &= args[1].type() == azrtti_typeid(); - validArgs &= args[2].type() == azrtti_typeid(); - } - - if (!validArgs) - { - AZ_Error("PassSystem", false, "[DiffuseProbeBlendIrradiancePass '%s']: Shader '%s' contains invalid numthreads arguments.", GetPathName().GetCStr(), shaderFilePath.c_str()); - return; - } - - m_dispatchArgs.m_threadsPerGroupX = static_cast(AZStd::any_cast(args[0])); - m_dispatchArgs.m_threadsPerGroupY = static_cast(AZStd::any_cast(args[1])); - m_dispatchArgs.m_threadsPerGroupZ = static_cast(AZStd::any_cast(args[2])); + AZ_Error("PassSystem", false, "[DiffuseProbeBlendIrradiancePass '%s']: Shader '%s' contains invalid numthreads arguments:\n%s", GetPathName().GetCStr(), shaderFilePath.c_str(), outcome.GetError().c_str()); } } diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.cpp index b251526cb4..6c72f904b9 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.cpp @@ -67,27 +67,10 @@ namespace AZ srgLayout = shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Pass); // retrieve the number of threads per thread group from the shader - const auto numThreads = shader->GetAsset()->GetAttribute(RHI::ShaderStage::Compute, Name{ "numthreads" }); - if (numThreads) + const auto outcome = RPI::GetComputeShaderNumThreads(shader->GetAsset(), dispatchArgs); + if (!outcome.IsSuccess()) { - const RHI::ShaderStageAttributeArguments& args = *numThreads; - bool validArgs = args.size() == 3; - if (validArgs) - { - validArgs &= args[0].type() == azrtti_typeid(); - validArgs &= args[1].type() == azrtti_typeid(); - validArgs &= args[2].type() == azrtti_typeid(); - } - - if (!validArgs) - { - AZ_Error("PassSystem", false, "[DiffuseProbeGridBorderUpdatePass '%s']: Shader '%s' contains invalid numthreads arguments.", GetPathName().GetCStr(), shaderFilePath.c_str()); - return; - } - - dispatchArgs.m_threadsPerGroupX = static_cast(AZStd::any_cast(args[0])); - dispatchArgs.m_threadsPerGroupY = static_cast(AZStd::any_cast(args[1])); - dispatchArgs.m_threadsPerGroupZ = static_cast(AZStd::any_cast(args[2])); + AZ_Error("PassSystem", false, "[DiffuseProbeGridBorderUpdatePass '%s']: Shader '%s' contains invalid numthreads arguments:\n%s", GetPathName().GetCStr(), shaderFilePath.c_str(), outcome.GetError().c_str()); } } diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp index 2690f90a7d..61540c3332 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp @@ -58,27 +58,10 @@ namespace AZ m_srgLayout = m_shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Pass); // retrieve the number of threads per thread group from the shader - const auto numThreads = m_shader->GetAsset()->GetAttribute(RHI::ShaderStage::Compute, Name{ "numthreads" }); - if (numThreads) + const auto outcome = RPI::GetComputeShaderNumThreads(m_shader->GetAsset(), m_dispatchArgs); + if (!outcome.IsSuccess()) { - const RHI::ShaderStageAttributeArguments& args = *numThreads; - bool validArgs = args.size() == 3; - if (validArgs) - { - validArgs &= args[0].type() == azrtti_typeid(); - validArgs &= args[1].type() == azrtti_typeid(); - validArgs &= args[2].type() == azrtti_typeid(); - } - - if (!validArgs) - { - AZ_Error("PassSystem", false, "[DiffuseProbeClassificationPass '%s']: Shader '%s' contains invalid numthreads arguments.", GetPathName().GetCStr(), shaderFilePath.c_str()); - return; - } - - m_dispatchArgs.m_threadsPerGroupX = static_cast(AZStd::any_cast(args[0])); - m_dispatchArgs.m_threadsPerGroupY = static_cast(AZStd::any_cast(args[1])); - m_dispatchArgs.m_threadsPerGroupZ = static_cast(AZStd::any_cast(args[2])); + AZ_Error("PassSystem", false, "[DiffuseProbeClassificationPass '%s']: Shader '%s' contains invalid numthreads arguments:\n%s", GetPathName().GetCStr(), shaderFilePath.c_str(), outcome.GetError().c_str()); } } diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.cpp index 67fb95a833..a1b236ed4d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.cpp @@ -58,27 +58,10 @@ namespace AZ m_srgLayout = m_shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Pass); // retrieve the number of threads per thread group from the shader - const auto numThreads = m_shader->GetAsset()->GetAttribute(RHI::ShaderStage::Compute, Name{ "numthreads" }); - if (numThreads) + const auto outcome = RPI::GetComputeShaderNumThreads(m_shader->GetAsset(), m_dispatchArgs); + if (!outcome.IsSuccess()) { - const RHI::ShaderStageAttributeArguments& args = *numThreads; - bool validArgs = args.size() == 3; - if (validArgs) - { - validArgs &= args[0].type() == azrtti_typeid(); - validArgs &= args[1].type() == azrtti_typeid(); - validArgs &= args[2].type() == azrtti_typeid(); - } - - if (!validArgs) - { - AZ_Error("PassSystem", false, "[DiffuseProbeRelocationPass '%s']: Shader '%s' contains invalid numthreads arguments.", GetPathName().GetCStr(), shaderFilePath.c_str()); - return; - } - - m_dispatchArgs.m_threadsPerGroupX = static_cast(AZStd::any_cast(args[0])); - m_dispatchArgs.m_threadsPerGroupY = static_cast(AZStd::any_cast(args[1])); - m_dispatchArgs.m_threadsPerGroupZ = static_cast(AZStd::any_cast(args[2])); + AZ_Error("PassSystem", false, "[DiffuseProbeRelocationPass '%s']: Shader '%s' contains invalid numthreads arguments:\n%s", GetPathName().GetCStr(), shaderFilePath.c_str(), outcome.GetError().c_str()); } } diff --git a/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetDispatchItem.cpp b/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetDispatchItem.cpp index 19f379b17d..fcf1402ae6 100644 --- a/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetDispatchItem.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetDispatchItem.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -79,15 +80,11 @@ namespace AZ m_dispatchItem.m_pipelineState = m_morphTargetShader->AcquirePipelineState(pipelineStateDescriptor); // Get the threads-per-group values from the compute shader [numthreads(x,y,z)] - const auto& numThreads = m_morphTargetShader->GetAsset()->GetAttribute(RHI::ShaderStage::Compute, AZ::Name{ "numthreads" }); auto& arguments = m_dispatchItem.m_arguments.m_direct; - if (numThreads) + const auto outcome = RPI::GetComputeShaderNumThreads(m_morphTargetShader->GetAsset(), arguments); + if (!outcome.IsSuccess()) { - const auto& args = *numThreads; - // Check that the arguments are valid integers, and fall back to 1,1,1 if there is an error - arguments.m_threadsPerGroupX = static_cast(args[0].type() == azrtti_typeid() ? AZStd::any_cast(args[0]) : 1); - arguments.m_threadsPerGroupY = static_cast(args[1].type() == azrtti_typeid() ? AZStd::any_cast(args[1]) : 1); - arguments.m_threadsPerGroupZ = static_cast(args[2].type() == azrtti_typeid() ? AZStd::any_cast(args[2]) : 1); + AZ_Error("MorphTargetDispatchItem", false, outcome.GetError().c_str()); } arguments.m_totalNumberOfThreadsX = m_morphTargetMetaData.m_vertexCount; diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshDispatchItem.cpp b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshDispatchItem.cpp index bfc533763e..5ec26cebde 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshDispatchItem.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshDispatchItem.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -199,17 +200,14 @@ namespace AZ m_instanceSrg->Compile(); m_dispatchItem.m_uniqueShaderResourceGroup = m_instanceSrg->GetRHIShaderResourceGroup(); m_dispatchItem.m_pipelineState = m_skinningShader->AcquirePipelineState(pipelineStateDescriptor); - - const auto& numThreads = m_skinningShader->GetAsset()->GetAttribute(RHI::ShaderStage::Compute, AZ::Name{ "numthreads" }); - auto& arguments = m_dispatchItem.m_arguments.m_direct; - if (numThreads) - { - const auto& args = *numThreads; - arguments.m_threadsPerGroupX = static_cast(args[0].type() == azrtti_typeid() ? AZStd::any_cast(args[0]) : 1); - arguments.m_threadsPerGroupY = static_cast(args[1].type() == azrtti_typeid() ? AZStd::any_cast(args[1]) : 1); - arguments.m_threadsPerGroupZ = static_cast(args[2].type() == azrtti_typeid() ? AZStd::any_cast(args[2]) : 1); - } + auto& arguments = m_dispatchItem.m_arguments.m_direct; + const auto outcome = RPI::GetComputeShaderNumThreads(m_skinningShader->GetAsset(), arguments); + if (!outcome.IsSuccess()) + { + AZ_Error("SkinnedMeshInputBuffers", false, outcome.GetError().c_str()); + } + arguments.m_totalNumberOfThreadsX = xThreads; arguments.m_totalNumberOfThreadsY = yThreads; arguments.m_totalNumberOfThreadsZ = 1; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPIUtils.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPIUtils.h index a2972ff0fd..3e92542429 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPIUtils.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPIUtils.h @@ -11,6 +11,7 @@ #include +#include #include #include #include @@ -40,6 +41,23 @@ namespace AZ //! Loads a streaming image asset for the given file path Data::Instance LoadStreamingTexture(AZStd::string_view path); + + //! Looks for a three arguments attribute named @attributeName in the given shader asset. + //! Assigns the value to each non-null output variables. + //! @param shaderAsset + //! @param attributeName + //! @param numThreadsX Can be NULL. If not NULL it takes the value of the 1st argument of the attribute. Becomes 1 on error. + //! @param numThreadsY Can be NULL. If not NULL it takes the value of the 2nd argument of the attribute. Becomes 1 on error. + //! @param numThreadsZ Can be NULL. If not NULL it takes the value of the 3rd argument of the attribute. Becomes 1 on error. + //! @returns An Outcome instance with error message in case of error. + AZ::Outcome GetComputeShaderNumThreads(const Data::Asset& shaderAsset, const AZ::Name& attributeName, uint16_t* numThreadsX, uint16_t* numThreadsY, uint16_t* numThreadsZ); + + //! Same as above, but assumes the name of the attribute to be 'numthreads'. + AZ::Outcome GetComputeShaderNumThreads(const Data::Asset& shaderAsset, uint16_t* numThreadsX, uint16_t* numThreadsY, uint16_t* numThreadsZ); + + //! Same as above. Provided as a convenience when all arguments of the 'numthreads' attributes should be assigned to RHI::DispatchDirect::m_threadsPerGroup* variables. + AZ::Outcome GetComputeShaderNumThreads(const Data::Asset& shaderAsset, RHI::DispatchDirect& dispatchDirect); + } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ComputePass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ComputePass.cpp index 2505409c62..8bcf9b1b85 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ComputePass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ComputePass.cpp @@ -107,30 +107,13 @@ namespace AZ dispatchArgs.m_totalNumberOfThreadsY = passData->m_totalNumberOfThreadsY; dispatchArgs.m_totalNumberOfThreadsZ = passData->m_totalNumberOfThreadsZ; - const auto numThreads = m_shader->GetAsset()->GetAttribute(RHI::ShaderStage::Compute, Name{ "numthreads" }); - if (numThreads) + const auto outcome = RPI::GetComputeShaderNumThreads(m_shader->GetAsset(), dispatchArgs); + if (!outcome.IsSuccess()) { - const RHI::ShaderStageAttributeArguments& args = *numThreads; - bool validArgs = args.size() == 3; - if (validArgs) - { - validArgs &= args[0].type() == azrtti_typeid(); - validArgs &= args[1].type() == azrtti_typeid(); - validArgs &= args[2].type() == azrtti_typeid(); - } - - if (!validArgs) - { - AZ_Error("PassSystem", false, "[ComputePass '%s']: Shader '%s' contains invalid numthreads arguments.", - GetPathName().GetCStr(), - passData->m_shaderReference.m_filePath.data()); - return; - } - - dispatchArgs.m_threadsPerGroupX = aznumeric_cast(AZStd::any_cast(args[0])); - dispatchArgs.m_threadsPerGroupY = aznumeric_cast(AZStd::any_cast(args[1])); - dispatchArgs.m_threadsPerGroupZ = aznumeric_cast(AZStd::any_cast(args[2])); + AZ_Error("PassSystem", false, "[ComputePass '%s']: Shader '%.*s' contains invalid numthreads arguments:\n%s", + GetPathName().GetCStr(), passData->m_shaderReference.m_filePath.size(), passData->m_shaderReference.m_filePath.data(), outcome.GetError().c_str()); } + m_dispatchItem.m_arguments = dispatchArgs; m_isFullscreenPass = passData->m_makeFullscreenPass; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RPIUtils.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RPIUtils.cpp index 9173b47fad..e70885daa1 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RPIUtils.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RPIUtils.cpp @@ -143,5 +143,79 @@ namespace AZ return RPI::StreamingImage::FindOrCreate(streamingImageAsset); } + + //! A helper function for GetComputeShaderNumThreads(), to consolidate error messages, etc. + static bool GetAttributeArgumentByIndex(const Data::Asset& shaderAsset, const AZ::Name& attributeName, const RHI::ShaderStageAttributeArguments& args, const size_t argIndex, uint16_t* value, AZStd::string& errorMsg) + { + if (value) + { + const auto numArguments = args.size(); + if (numArguments > argIndex) + { + if (args[argIndex].type() == azrtti_typeid()) + { + *value = aznumeric_caster(AZStd::any_cast(args[argIndex])); + } + else + { + errorMsg = AZStd::string::format("Was expecting argument '%zu' in attribute '%s' to be of type 'int' from shader asset '%s'", argIndex, attributeName.GetCStr(), shaderAsset.GetHint().c_str()); + return false; + } + } + else + { + errorMsg = AZStd::string::format("Was expecting at least '%zu' arguments in attribute '%s' from shader asset '%s'", argIndex + 1, attributeName.GetCStr(), shaderAsset.GetHint().c_str()); + return false; + } + } + return true; + } + + AZ::Outcome GetComputeShaderNumThreads(const Data::Asset& shaderAsset, const AZ::Name& attributeName, uint16_t* numThreadsX, uint16_t* numThreadsY, uint16_t* numThreadsZ) + { + // Set default 1, 1, 1 now. In case of errors later this is what the caller will get. + if (numThreadsX) + { + *numThreadsX = 1; + } + if (numThreadsY) + { + *numThreadsY = 1; + } + if (numThreadsZ) + { + *numThreadsZ = 1; + } + const auto numThreads = shaderAsset->GetAttribute(RHI::ShaderStage::Compute, attributeName); + if (!numThreads) + { + return AZ::Failure(AZStd::string::format("Couldn't find attribute '%s' in shader asset '%s'", attributeName.GetCStr(), shaderAsset.GetHint().c_str())); + } + const RHI::ShaderStageAttributeArguments& args = *numThreads; + AZStd::string errorMsg; + if (!GetAttributeArgumentByIndex(shaderAsset, attributeName, args, 0, numThreadsX, errorMsg)) + { + return AZ::Failure(errorMsg); + } + if (!GetAttributeArgumentByIndex(shaderAsset, attributeName, args, 1, numThreadsY, errorMsg)) + { + return AZ::Failure(errorMsg); + } + if (!GetAttributeArgumentByIndex(shaderAsset, attributeName, args, 2, numThreadsZ, errorMsg)) + { + return AZ::Failure(errorMsg); + } + return AZ::Success(); + } + + AZ::Outcome GetComputeShaderNumThreads(const Data::Asset& shaderAsset, uint16_t* numThreadsX, uint16_t* numThreadsY, uint16_t* numThreadsZ) + { + return GetComputeShaderNumThreads(shaderAsset, Name{ "numthreads" }, numThreadsX, numThreadsY, numThreadsZ); + } + + AZ::Outcome GetComputeShaderNumThreads(const Data::Asset& shaderAsset, RHI::DispatchDirect& dispatchDirect) + { + return GetComputeShaderNumThreads(shaderAsset, &dispatchDirect.m_threadsPerGroupX, &dispatchDirect.m_threadsPerGroupY, &dispatchDirect.m_threadsPerGroupZ); + } } } From f648cb1fd88ceeacada17e827d944bf124a195d0 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Tue, 5 Oct 2021 15:12:53 -0500 Subject: [PATCH 24/27] Update the FileIO Aliases (#4186) * Update the FileIOAlias naming to make the cache, project root and engine root paths more clear The alias of `@root@`, `@assets@`, and `@projectplatformcache@` has been collapsed to `@projectproductassets@` The alias of `@devroot@` and `@engroot@` has been collapsed to `@engroot@` The alias of `@devassets@` and `@projectroot@` has been collapsed to `@projectroot@` Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated use of devassets and devroot properties in python Those properties now use projectroot and engroot Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updating the alias @engroot@ alias path comment in each platform specific LocalFileIO_*.cpp file Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed hardcoded size of 9 for the product asset alias. The ResolvePath function now just appends the @projectproductassets@ alias with the input path Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Remove duplicate @projectproductassets@ check in ProcessFileTreeRequest Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Fix for typos in Hydra python test Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated LocalFileIO::Copy call on Windows to use the Unicode aware CopyFileW API Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the AWSMetreicsGemAllocatorFixture to properly suppress asset cache write errors for Test file creation. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed unneeded call to set the @projectproductasstes@ alias at the bottom of the AssetSeedManagerTest SetUp Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Added a deprecated alias map to the FileIO System When a deprecated alias is accessed, the FileIO System logs an AZ_Error and indicates the alias that should be used Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated python test scripts to use the projectroot binding Retrieving the AutomatedTesting project path based on "/AutomatedTesting" has been removed. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated references to devroot and devgame within the codebase The GetAbsoluteDevGameFolderPath functions has been replaced with direct call to AZ::Utils::GetProjectPath The GetAbsoluteDevRootFolderPath functions has been replaced with direct calls to AZ::Utils::GetEnginePath Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated /AutomatedTesting references to projectroot Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Replaced references that assumes the project path is /AutomatedTesting with in the AutomatedTesting python test Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Correct casing in emfxworkspace file Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed newly added AppendPathParts function Removed the Path constructors which accepts a PathIterable instance The PathIterable isn't safe to return to a user of the Path class as it might be referencing temporary paths supplied via PathView arguments Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Fixed unused parameter warning Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Undid change to the LexicallyProximate function to set the path result to the base path. It needs to return the *this path if the pathResult is empty Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Moved the LocalFileIO ConvertToAbsolutePath implementations to AZ::Utils Fixed the ConvertToAbsolutePath implementation for Unix platforms to use a buffer that is size PATH_MAX(4096 on all our supported Unix platforms). Because the buffer before was AZ::IO::MaxPathLength which as a size of 1024, this was resulting in the Unix `realpath` function smashing the stack when it converts a path to an absolute path that is longer than 1024 characters Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the EditorCore.Tests to attach the AZ Environment to the EditorCore shared library that is statically loaded on launch. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Fixed for DeprecatedAlaisesKeyVisitor Visit function causing the non string_view overloads being hidden causing a hidden base class function warning Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Changed the AWSMetricsGemMock to use a temporary for writing test assets Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the LocalFileIO::ResolvePath function to use HasRootPath to determine if a path starts with a root path such as "D:", "D:/" or "/" IsAbsolute was not the corect check as the path of "D:" is a relative path. To be absolute according to the Windows the path must have a root directory. i.e "D:/" or "D:\" Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed absolute path comment from LocalFile_UnixLike.cpp and LocalFile_Android.cpp FindFiles implementations Updated the ConvertToAlias to supply an AZ::IO::FixedMaxPath Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Replaced usage of the @projectproductassets@ alias with @engroot@ when referring to the LmbrCentral source folder in the CopyDependencyBuilderTest and the SeedBuilderTests Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the ScriptCanvas Upgrade Tool to output backed up files to the Project User Path instead of the engine root Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Fixed whitespacing issues in Application.cpp Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Remove unnecessary creation of a FixedMaxPath in the UpgradeTool.cpp Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Modified testSeedFolder variable in the SeedBuilderTests to use the @engroot@ alias instead of @projectproductassets@/.. alias when referring to the LmbrCentral Gem source path Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated references to the Project Asset Cache in the PythonTests. Those tests no longer use the logic `azlmbr.paths.projectroot / "Cache" / "pc"` to retrieve a path to the cache root but instead the `azlmbr.paths.projectproductassets` constant Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Fixed the FileIO Deprecated Alias test on Windows Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removing @projectsourceassets@ alias, as it is only used once. Updated the PhysX EditorSystemComponent.cpp to query the ProjectPath form the SettingsRegistry. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Replaced @projectproductassets@ alias with @products@ Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Rollback changes to the PhysX EditorSystemComponent.cpp The changes to use the ProjectPath from the SettingsRegistry has been implemented in PR #4497 Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- Assets/Engine/exclude.filetag | 32 --- .../Atom/atom_utils/material_editor_utils.py | 2 +- ...ydra_AtomEditorComponents_AddedToEntity.py | 2 +- ...dra_AtomEditorComponents_LightComponent.py | 2 +- .../hydra_AtomMaterialEditor_BasicTests.py | 16 +- ...GPUTest_AtomFeatureIntegrationBenchmark.py | 2 +- .../tests/hydra_GPUTest_BasicLevelSetup.py | 2 +- .../tests/hydra_GPUTest_LightComponent.py | 2 +- .../EditorCommandLine_test.py | 1 - .../EditorCommandLine_test_case.py | 6 - .../ComponentUpdateListProperty_test_case.py | 2 +- .../LevelComponentCommands.cfg | 2 +- .../ViewportTitleDlgCommands.cfg | 2 +- ...ynamicSliceInstanceSpawner_Embedded_E2E.py | 2 +- ...ynamicSliceInstanceSpawner_External_E2E.py | 2 +- .../EditorScripts/LayerBlender_E2E_Editor.py | 2 +- .../editor_dynveg_test_helper.py | 6 +- .../cowboy.emfxworkspace | 2 +- .../ws.emfxworkspace | 2 +- Code/Editor/Controls/FolderTreeCtrl.cpp | 13 +- Code/Editor/Core/Tests/test_Main.cpp | 2 + Code/Editor/Core/Tests/test_PathUtil.cpp | 37 ++-- Code/Editor/CryEdit.cpp | 2 +- Code/Editor/CryEditDoc.cpp | 4 +- Code/Editor/Dialogs/PythonScriptsDialog.cpp | 2 +- Code/Editor/EditorFileMonitor.cpp | 36 +--- .../SandboxIntegration.cpp | 2 +- .../AssetImporterWindow.cpp | 79 +++---- .../SceneSerializationHandler.cpp | 25 +-- .../ProjectSettingsToolWindow.cpp | 1 - .../ProjectSettingsToolWindow.h | 1 - .../Plugins/ProjectSettingsTool/Utils.cpp | 34 ++- .../Plugins/ProjectSettingsTool/Utils.h | 2 +- Code/Editor/Settings.cpp | 5 +- .../TrackView/SequenceBatchRenderDialog.cpp | 26 +-- Code/Editor/Util/PathUtil.cpp | 200 +++--------------- Code/Editor/Util/PathUtil.h | 90 -------- Code/Framework/AzCore/AzCore/IO/FileIO.h | 15 +- Code/Framework/AzCore/AzCore/IO/IStreamer.h | 32 +-- Code/Framework/AzCore/AzCore/IO/Path/Path.h | 54 +++-- Code/Framework/AzCore/AzCore/IO/Path/Path.inl | 83 +++++--- .../AzCore/AzCore/IO/Path/PathIterable.inl | 2 +- .../Settings/SettingsRegistryMergeUtils.cpp | 6 +- .../AzCore/UnitTest/Mocks/MockFileIOBase.h | 1 + Code/Framework/AzCore/AzCore/Utils/Utils.cpp | 14 ++ Code/Framework/AzCore/AzCore/Utils/Utils.h | 1 + .../Android/AzCore/Utils/Utils_Android.cpp | 33 ++- .../UnixLike/AzCore/Utils/Utils_UnixLike.cpp | 31 ++- .../WinAPI/AzCore/Utils/Utils_WinAPI.cpp | 17 +- .../AzCore/Tests/FileIOBaseTestTypes.h | 4 + .../AzCore/Tests/IO/Path/PathTests.cpp | 2 +- .../AzFramework/Application/Application.cpp | 89 ++++++-- .../AzFramework/Archive/Archive.cpp | 6 +- .../AzFramework/Archive/ArchiveFileIO.cpp | 10 + .../AzFramework/Archive/ArchiveFileIO.h | 1 + .../AzFramework/Archive/ArchiveFindData.cpp | 18 +- .../AzFramework/Archive/MissingFileReport.cpp | 2 +- .../AzFramework/Asset/AssetCatalog.cpp | 2 +- .../AzFramework/AzFramework/Gem/GemInfo.cpp | 2 +- .../AzFramework/IO/LocalFileIO.cpp | 119 ++++++++--- .../AzFramework/AzFramework/IO/LocalFileIO.h | 6 +- .../AzFramework/IO/RemoteFileIO.cpp | 30 ++- .../AzFramework/AzFramework/IO/RemoteFileIO.h | 2 + .../AzFramework/IO/LocalFileIO_Android.cpp | 62 ++---- .../AzFramework/IO/LocalFileIO_UnixLike.cpp | 50 ++--- .../AzFramework/IO/LocalFileIO_WinAPI.cpp | 33 +-- .../AzFramework/IO/LocalFileIO_Windows.cpp | 32 ++- .../AzFramework/Tests/Application.cpp | 2 +- .../AzFramework/Tests/ArchiveTests.cpp | 62 +++--- Code/Framework/AzFramework/Tests/FileIO.cpp | 45 ++++ .../AzFramework/Tests/FileTagTests.cpp | 18 +- .../AzFramework/Tests/GenAppDescriptors.cpp | 110 ++++------ .../Application/GameApplication.cpp | 4 +- .../Utilities/EncryptionCommon.cpp | 2 +- .../API/EditorAssetSystemAPI.h | 8 - .../Asset/AssetSystemComponent.cpp | 20 -- .../Asset/AssetSystemComponent.h | 2 - .../AssetEditor/AssetEditorWidget.cpp | 2 +- .../AzToolsFramework/Debug/TraceContext.h | 2 +- .../AzToolsFramework/Logger/TraceLogger.cpp | 2 +- .../Slice/SliceRequestComponent.cpp | 9 +- .../Slice/SliceTransaction.cpp | 6 +- .../ToolsComponents/EditorLayerComponent.cpp | 4 +- .../UI/Prefab/PrefabIntegrationManager.cpp | 2 +- .../AzToolsFramework/Tests/ArchiveTests.cpp | 4 +- .../Tests/AssetSeedManager.cpp | 34 ++- .../AzToolsFramework/Tests/AssetSystemMocks.h | 2 - .../AzToolsFramework/Tests/EntityTestbed.h | 4 +- .../PlatformAddressedAssetCatalogTests.cpp | 8 +- .../SliceStabilityTestFramework.h | 2 - Code/Legacy/CryCommon/CryPath.h | 6 +- Code/Legacy/CrySystem/ConsoleBatchFile.cpp | 6 +- Code/Legacy/CrySystem/DebugCallStack.cpp | 2 +- .../CrySystem/LevelSystem/LevelSystem.cpp | 2 +- Code/Legacy/CrySystem/SystemCFG.cpp | 10 +- Code/Legacy/CrySystem/SystemInit.cpp | 9 +- .../Android/InitializeCerts_Android.cpp | 2 +- .../AssetBuilder/AssetBuilderComponent.cpp | 17 +- .../native/AssetManager/AssetCatalog.cpp | 46 ++-- .../native/AssetManager/AssetCatalog.h | 4 - .../AssetManager/assetProcessorManager.cpp | 9 +- .../AssetManager/assetProcessorManager.h | 2 - .../native/FileServer/fileServer.cpp | 16 +- .../AssetCatalog/AssetCatalogUnitTests.cpp | 4 +- .../unittests/RCcontrollerUnitTests.cpp | 26 +-- .../native/unittests/UnitTestRunner.h | 3 +- .../utilities/GUIApplicationManager.cpp | 9 +- .../CrashHandler/Tools/ToolsCrashHandler.cpp | 2 +- .../tests/ApplicationTests.cpp | 2 +- .../SceneCore/Export/MtlMaterialExporter.cpp | 13 +- .../SerializeContextTools/SliceConverter.cpp | 8 +- .../Configuration/AWSCoreConfiguration.cpp | 2 +- .../Source/Editor/UI/AWSCoreEditorMenu.cpp | 2 +- .../AWSCoreConfigurationTest.cpp | 6 +- .../Tests/Editor/UI/AWSCoreEditorMenuTest.cpp | 2 +- .../Code/Source/IdentityProvider.cpp | 2 +- .../AWSMetrics/Code/Tests/AWSMetricsGemMock.h | 40 ++-- .../Source/AssetValidationSystemComponent.cpp | 8 +- .../BuilderSettings/BuilderSettingManager.cpp | 2 +- .../Editor/ShaderVariantAssetBuilder.cpp | 44 ++-- Gems/Atom/RHI/Code/Tests/UtilsTests.cpp | 2 +- .../Include/Atom/RPI.Edit/Common/AssetUtils.h | 10 +- .../RPI/Code/Tests/Common/AssetSystemStub.cpp | 10 - .../RPI/Code/Tests/Common/AssetSystemStub.h | 2 - .../RPI/Code/Tests/Common/RPITestFixture.cpp | 6 +- .../Application/AtomToolsApplication.cpp | 6 +- .../CreateMaterialDialog.cpp | 2 +- .../MaterialEditorBrowserInteractions.cpp | 4 +- .../ViewportSettingsInspector.cpp | 2 +- .../Scripts/GenerateAllMaterialScreenshots.py | 6 +- .../GenerateShaderVariantListForMaterials.py | 2 +- .../AtomFont/Code/Source/AtomFont.cpp | 2 +- .../EditorDiffuseProbeGridComponent.cpp | 4 +- .../EditorMaterialComponentInspector.cpp | 2 +- .../EditorReflectionProbeComponent.cpp | 2 +- .../Builder/AudioControlBuilderWorker.cpp | 10 +- .../Source/Builder/WwiseBuilderWorker.cpp | 8 +- .../Tests/AudioEngineWwiseBuilderTest.cpp | 16 +- .../Code/Tests/AudioEngineWwiseTest.cpp | 20 +- .../Code/Source/Engine/ATLComponents.cpp | 2 +- .../Components/BlastSystemComponent.cpp | 4 +- .../Code/Source/DataSource/FileDataSource.cpp | 14 +- .../EMotionFX/Source/EMotionFXManager.cpp | 14 +- .../EMStudioSDK/Source/FileManager.cpp | 22 +- .../EMStudioSDK/Source/MainWindow.cpp | 28 +-- .../EMStudioSDK/Source/Workspace.cpp | 2 +- .../Integration/Assets/AnimGraphAsset.cpp | 14 +- .../Integration/Assets/MotionSetAsset.cpp | 20 +- .../Integration/System/SystemComponent.cpp | 6 +- ...MotionSetWhenSameMotionInTwoMotionSets.cpp | 6 +- .../Code/Tests/CommandRemoveMotionTests.cpp | 2 +- .../Code/Tests/EMotionFXBuilderTests.cpp | 16 +- .../Tests/Editor/MotionSetLoadEscalation.cpp | 2 +- .../Tests/Game/SamplePerformanceTests.cpp | 18 +- .../Code/Tests/Integration/CanAddActor.cpp | 2 +- .../Tests/Integration/PoseComparisonTests.cpp | 24 +-- .../AnimGraph/PreviewMotionFixture.cpp | 6 +- .../ProvidesUI/Menus/FileMenu/CanReset.cpp | 2 +- .../ProvidesUI/Motions/CanAddMotions.cpp | 2 +- .../Motions/MotionPlaybacksTests.cpp | 2 +- .../Code/Tests/UI/CanAutoSaveFile.cpp | 2 +- .../Code/Tests/UI/CanUseFileMenu.cpp | 2 +- .../Assets/release_notes.md | 2 +- .../Code/Source/PythonReflectionComponent.cpp | 12 +- .../Code/Source/PythonSystemComponent.cpp | 4 +- .../Code/Tests/PythonBindingLibTests.cpp | 8 +- .../Tests/PythonReflectionComponentTests.cpp | 13 +- .../Code/Tests/PythonTestingUtility.h | 1 - .../GameStateLevelLoading.inl | 2 +- .../GameStateSamples/GameStateLevelPaused.inl | 2 +- .../GameStateLevelRunning.inl | 2 +- .../GameStateLocalUserLobby.inl | 4 +- .../GameStateSamples/GameStateMainMenu.inl | 2 +- .../GameStateSamples/GameStateOptionsMenu.inl | 2 +- .../GameStatePrimaryUserSelection.inl | 2 +- .../GraphCanvas/Styling/StyleManager.cpp | 12 +- .../Android/InAppPurchasesAndroid.cpp | 10 +- .../EmfxWorkspaceBuilderWorker.cpp | 8 +- .../LevelBuilder/LevelBuilderWorker.cpp | 2 +- .../MaterialBuilderComponent.cpp | 48 ++--- .../Bundling/BundlingSystemComponent.cpp | 4 +- Gems/LmbrCentral/Code/Source/LmbrCentral.cpp | 2 +- .../Builders/CopyDependencyBuilderTest.cpp | 14 +- .../Code/Tests/Builders/LevelBuilderTest.cpp | 6 +- .../Code/Tests/Builders/LuaBuilderTests.cpp | 4 +- .../Tests/Builders/MaterialBuilderTests.cpp | 17 +- .../Code/Tests/Builders/SeedBuilderTests.cpp | 10 +- .../Tests/BundlingSystemComponentTests.cpp | 46 ++-- .../productdependencies.emfxworkspace | 2 +- .../Code/Tests/Materials/test_mat17.mtl | 2 +- Gems/LyShine/Code/Editor/EditorMenu.cpp | 10 +- Gems/LyShine/Code/Editor/UiSliceManager.cpp | 6 +- Gems/LyShine/Code/Source/UiCanvasManager.cpp | 12 +- Gems/LyShine/Code/Tests/LyShineEditorTest.cpp | 8 +- .../Code/Source/LyShineMessagePopup.cpp | 8 +- .../AnimationEditorFiles/Cowboy.emfxworkspace | 2 +- .../Source/QtForPythonSystemComponent.cpp | 3 - .../Tests/SceneBuilder/SceneBuilderTests.cpp | 15 +- .../ScriptCanvas/Assets/ScriptCanvasAsset.h | 2 +- .../CommonSettingsConfigurations.cpp | 19 +- .../Code/Editor/View/Windows/MainWindow.cpp | 133 ++++++------ .../Code/Editor/View/Windows/MainWindow.h | 2 +- .../Windows/Tools/UpgradeTool/UpgradeTool.cpp | 60 ++---- .../Windows/Tools/UpgradeTool/UpgradeTool.h | 3 +- .../Tools/UpgradeTool/VersionExplorer.cpp | 71 ++----- .../ScriptCanvas/Asset/ExecutionLogAsset.cpp | 2 +- .../Include/ScriptCanvas/Asset/RuntimeAsset.h | 4 +- .../Code/Source/EditorWhiteBoxComponent.cpp | 17 +- Registry/fileio.setreg | 26 +++ 209 files changed, 1365 insertions(+), 1678 deletions(-) create mode 100644 Registry/fileio.setreg diff --git a/Assets/Engine/exclude.filetag b/Assets/Engine/exclude.filetag index 52534a87d8..3528454ec4 100644 --- a/Assets/Engine/exclude.filetag +++ b/Assets/Engine/exclude.filetag @@ -125,17 +125,6 @@
- - - - - - - - - - - @@ -207,27 +196,6 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/material_editor_utils.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/material_editor_utils.py index ef0a592df0..b21c74de19 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/material_editor_utils.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/material_editor_utils.py @@ -211,7 +211,7 @@ class Timeout: return time.time() > self.die_after -screenshotsFolder = os.path.join(azlmbr.paths.devroot, "AtomTest", "Cache" "pc", "Screenshots") +screenshotsFolder = os.path.join(azlmbr.paths.products, "Screenshots") class ScreenshotHelper: diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_AddedToEntity.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_AddedToEntity.py index 602e7564b3..bbc8463152 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_AddedToEntity.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_AddedToEntity.py @@ -17,7 +17,7 @@ import azlmbr.legacy.general as general import azlmbr.editor as editor import azlmbr.render as render -sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests")) +sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests")) import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.utils import TestHelper diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightComponent.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightComponent.py index 751f425916..7ecdc6859b 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightComponent.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightComponent.py @@ -14,7 +14,7 @@ import azlmbr.math as math import azlmbr.paths import azlmbr.legacy.general as general -sys.path.append(os.path.join(azlmbr.paths.devassets, "Gem", "PythonTests")) +sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests")) import editor_python_test_tools.hydra_editor_utils as hydra from Atom.atom_utils.atom_constants import LIGHT_TYPES diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomMaterialEditor_BasicTests.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomMaterialEditor_BasicTests.py index 88a1ef4c7b..9f8f6c44b2 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomMaterialEditor_BasicTests.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomMaterialEditor_BasicTests.py @@ -16,7 +16,7 @@ import time import azlmbr.math as math import azlmbr.paths -sys.path.append(os.path.join(azlmbr.paths.devassets, "Gem", "PythonTests")) +sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests")) import Atom.atom_utils.material_editor_utils as material_editor @@ -27,10 +27,10 @@ TEST_MATERIAL_1 = "001_DefaultWhite.material" TEST_MATERIAL_2 = "002_BaseColorLerp.material" TEST_MATERIAL_3 = "003_MetalMatte.material" TEST_DATA_PATH = os.path.join( - azlmbr.paths.devroot, "Gems", "Atom", "TestData", "TestData", "Materials", "StandardPbrTestCases" + azlmbr.paths.engroot, "Gems", "Atom", "TestData", "TestData", "Materials", "StandardPbrTestCases" ) MATERIAL_TYPE_PATH = os.path.join( - azlmbr.paths.devroot, "Gems", "Atom", "Feature", "Common", "Assets", + azlmbr.paths.engroot, "Gems", "Atom", "Feature", "Common", "Assets", "Materials", "Types", "StandardPBR.materialtype", ) CACHE_FILE_EXTENSION = ".azmaterial" @@ -61,7 +61,7 @@ def run(): print(f"Material opened: {material_editor.is_open(document_id)}") # Verify if the test material exists initially - target_path = os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Materials", NEW_MATERIAL) + target_path = os.path.join(azlmbr.paths.projectroot, "Materials", NEW_MATERIAL) print(f"Test asset doesn't exist initially: {not os.path.exists(target_path)}") # 2) Test Case: Creating a New Material Using Existing One @@ -109,10 +109,10 @@ def run(): # Assign new color to the material file and save the document as copy expected_color_1 = math.Color(0.5, 0.5, 0.5, 1.0) material_editor.set_property(document_id, property_name, expected_color_1) - target_path_1 = os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Materials", NEW_MATERIAL_1) + target_path_1 = os.path.join(azlmbr.paths.projectroot, "Materials", NEW_MATERIAL_1) cache_file_name_1 = os.path.splitext(NEW_MATERIAL_1) # Example output: ('test_material_1', '.material') cache_file_1 = f"{cache_file_name_1[0]}{CACHE_FILE_EXTENSION}" - target_path_1_cache = os.path.join(azlmbr.paths.devassets, "Cache", "pc", "materials", cache_file_1) + target_path_1_cache = os.path.join(azlmbr.paths.products, "materials", cache_file_1) material_editor.save_document_as_copy(document_id, target_path_1) material_editor.wait_for_condition(lambda: os.path.exists(target_path_1_cache), 4.0) @@ -120,10 +120,10 @@ def run(): # Assign new color to the material file save the document as child expected_color_2 = math.Color(0.75, 0.75, 0.75, 1.0) material_editor.set_property(document_id, property_name, expected_color_2) - target_path_2 = os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Materials", NEW_MATERIAL_2) + target_path_2 = os.path.join(azlmbr.paths.projectroot, "Materials", NEW_MATERIAL_2) cache_file_name_2 = os.path.splitext(NEW_MATERIAL_1) # Example output: ('test_material_2', '.material') cache_file_2 = f"{cache_file_name_2[0]}{CACHE_FILE_EXTENSION}" - target_path_2_cache = os.path.join(azlmbr.paths.devassets, "Cache", "pc", "materials", cache_file_2) + target_path_2_cache = os.path.join(azlmbr.paths.products, "materials", cache_file_2) material_editor.save_document_as_child(document_id, target_path_2) material_editor.wait_for_condition(lambda: os.path.exists(target_path_2_cache), 4.0) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py index 4f7edeba75..92199bf196 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py @@ -10,7 +10,7 @@ import sys import azlmbr.legacy.general as general -sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests")) +sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests")) import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.editor_test_helper import EditorTestHelper diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py index 62a122a723..ac28e67fa1 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py @@ -17,7 +17,7 @@ import azlmbr.math as math import azlmbr.paths import azlmbr.editor as editor -sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests")) +sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests")) import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.editor_test_helper import EditorTestHelper diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_LightComponent.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_LightComponent.py index 4a3ae8c85d..1c3e6226c1 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_LightComponent.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_LightComponent.py @@ -14,7 +14,7 @@ import azlmbr.math as math import azlmbr.paths import azlmbr.legacy.general as general -sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests")) +sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests")) import editor_python_test_tools.hydra_editor_utils as hydra from Atom.atom_utils import atom_component_helper, atom_constants, screenshot_utils diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorCommandLine_test.py b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorCommandLine_test.py index 1d3ca11618..fcce6eab37 100755 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorCommandLine_test.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorCommandLine_test.py @@ -42,7 +42,6 @@ class TestEditorAutomation(object): "editor command line arg bar", "editor command line arg baz", "editor engroot set", - "editor devroot set", "path resolved worked" ] diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorCommandLine_test_case.py b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorCommandLine_test_case.py index bd8791fad6..c6ae65612f 100755 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorCommandLine_test_case.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorCommandLine_test_case.py @@ -20,12 +20,6 @@ if (engroot is not None and len(engroot) is not 0): print ('engroot is {}'.format(engroot)) print ('editor engroot set') -# make sure the @devroot@ exists as a azlmbr.paths property -devroot = azlmbr.paths.devroot -if (devroot is not None and len(devroot) != 0): - print ('devroot is {}'.format(devroot)) - print ('editor devroot set') - # resolving a basic path path = azlmbr.paths.resolve_path('@engroot@/engineassets/texturemsg/defaultsolids.mtl') if (len(path) != 0 and path.find('@engroot@') == -1): diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorScripts/ComponentUpdateListProperty_test_case.py b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorScripts/ComponentUpdateListProperty_test_case.py index 5b7f2f42c1..c5ca4de603 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorScripts/ComponentUpdateListProperty_test_case.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorScripts/ComponentUpdateListProperty_test_case.py @@ -16,7 +16,7 @@ import azlmbr.entity as entity import azlmbr.math as math import azlmbr.paths -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) +sys.path.append(os.path.join(azlmbr.paths.projectroot, 'Gem', 'PythonTests')) from automatedtesting_shared.editor_test_helper import EditorTestHelper diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/LevelComponentCommands.cfg b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/LevelComponentCommands.cfg index 3adc32d20a..ccc605cec9 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/LevelComponentCommands.cfg +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/LevelComponentCommands.cfg @@ -1,2 +1,2 @@ # this file is copied to $/dev/editor_autoexec.cfg so the the Editor automation runs for this Hydra test -pyRunFile @devroot@/Tests/hydra/LevelComponentCommands_test_case.py exit_when_done \ No newline at end of file +pyRunFile @engroot@/Tests/hydra/LevelComponentCommands_test_case.py exit_when_done \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/ViewportTitleDlgCommands.cfg b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/ViewportTitleDlgCommands.cfg index 6230dfe0fa..3cbd84c1b5 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/ViewportTitleDlgCommands.cfg +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/ViewportTitleDlgCommands.cfg @@ -1,2 +1,2 @@ # this file is copied to $/dev/editor_autoexec.cfg so the the Editor automation runs for this Hydra test -pyRunFile @devroot@/Tests/hydra/ViewportTitleDlgCommands_test_case.py \ No newline at end of file +pyRunFile @engroot@/Tests/hydra/ViewportTitleDlgCommands_test_case.py \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_Embedded_E2E.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_Embedded_E2E.py index e51be58ec6..84c661873c 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_Embedded_E2E.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_Embedded_E2E.py @@ -109,7 +109,7 @@ def DynamicSliceInstanceSpawner_Embedded_E2E(): # 6) Save and export to engine general.save_level() general.export_to_engine() - pak_path = os.path.join(paths.devroot, "AutomatedTesting", "cache", "pc", "levels", lvl_name, "level.pak") + pak_path = os.path.join(paths.products, "levels", lvl_name, "level.pak") Report.result(Tests.saved_and_exported, os.path.exists(pak_path)) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_External_E2E.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_External_E2E.py index 7a0abdd969..de2554034f 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_External_E2E.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_External_E2E.py @@ -131,7 +131,7 @@ def DynamicSliceInstanceSpawner_External_E2E(): # 6) Save and export to engine general.save_level() general.export_to_engine() - pak_path = os.path.join(paths.devroot, "AutomatedTesting", "cache", "pc", "levels", lvl_name, "level.pak") + pak_path = os.path.join(paths.products, "levels", lvl_name, "level.pak") Report.result(Tests.saved_and_exported, os.path.exists(pak_path)) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlender_E2E_Editor.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlender_E2E_Editor.py index f56c0b836e..bf6501f469 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlender_E2E_Editor.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlender_E2E_Editor.py @@ -155,7 +155,7 @@ def LayerBlender_E2E_Editor(): # 6) Save and export to engine general.save_level() general.export_to_engine() - pak_path = os.path.join(paths.devroot, "AutomatedTesting", "cache", "pc", "levels", lvl_name, "level.pak") + pak_path = os.path.join(paths.products, "levels", lvl_name, "level.pak") Report.result(Tests.saved_and_exported, os.path.exists(pak_path)) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/large_worlds_utils/editor_dynveg_test_helper.py b/AutomatedTesting/Gem/PythonTests/largeworlds/large_worlds_utils/editor_dynveg_test_helper.py index 65ebf8e59e..957536fffb 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/large_worlds_utils/editor_dynveg_test_helper.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/large_worlds_utils/editor_dynveg_test_helper.py @@ -17,7 +17,7 @@ import azlmbr.vegetation as vegetation import azlmbr.areasystem as areasystem import azlmbr.paths -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) +sys.path.append(os.path.join(azlmbr.paths.projectroot, 'Gem', 'PythonTests')) import editor_python_test_tools.hydra_editor_utils as hydra @@ -25,7 +25,7 @@ def create_surface_entity(name, center_point, box_size_x, box_size_y, box_size_z # Create a "flat surface" entity to use as a plantable vegetation surface surface_entity = hydra.Entity(name) surface_entity.create_entity( - center_point, + center_point, ["Box Shape", "Shape Surface Tag Emitter"] ) if surface_entity.id.IsValid(): @@ -56,7 +56,7 @@ def create_vegetation_area(name, center_point, box_size_x, box_size_y, box_size_ # Create a vegetation area entity to use as our test vegetation spawner spawner_entity = hydra.Entity(name) spawner_entity.create_entity( - center_point, + center_point, ["Vegetation Layer Spawner", "Box Shape", "Vegetation Asset List"] ) if spawner_entity.id.IsValid(): diff --git a/AutomatedTesting/Levels/Physics/Material_DefaultLibraryConsistentOnAllFeatures/cowboy.emfxworkspace b/AutomatedTesting/Levels/Physics/Material_DefaultLibraryConsistentOnAllFeatures/cowboy.emfxworkspace index 188fee9f05..05140f340b 100644 --- a/AutomatedTesting/Levels/Physics/Material_DefaultLibraryConsistentOnAllFeatures/cowboy.emfxworkspace +++ b/AutomatedTesting/Levels/Physics/Material_DefaultLibraryConsistentOnAllFeatures/cowboy.emfxworkspace @@ -1,3 +1,3 @@ [General] version=1 -startScript="ImportActor -filename \"@assets@/characters/cowboy/actor/cowboy_01.actor\"\nCreateActorInstance -actorID %LASTRESULT% -xPos 0.000000 -yPos 0.000000 -zPos 0.000000 -xScale 1.000000 -yScale 1.000000 -zScale 1.000000 -rot 0.00000000,0.00000000,0.00000000,1.00000000\n" +startScript="ImportActor -filename \"@products@/characters/cowboy/actor/cowboy_01.actor\"\nCreateActorInstance -actorID %LASTRESULT% -xPos 0.000000 -yPos 0.000000 -zPos 0.000000 -xScale 1.000000 -yScale 1.000000 -zScale 1.000000 -rot 0.00000000,0.00000000,0.00000000,1.00000000\n" diff --git a/AutomatedTesting/Levels/Physics/Material_DefaultMaterialLibraryChangesWork/ws.emfxworkspace b/AutomatedTesting/Levels/Physics/Material_DefaultMaterialLibraryChangesWork/ws.emfxworkspace index e429d74a57..870b9a8579 100644 --- a/AutomatedTesting/Levels/Physics/Material_DefaultMaterialLibraryChangesWork/ws.emfxworkspace +++ b/AutomatedTesting/Levels/Physics/Material_DefaultMaterialLibraryChangesWork/ws.emfxworkspace @@ -1,3 +1,3 @@ [General] version=1 -startScript="ImportActor -filename \"@assets@/levels/physics/c15096734_physxmaterials_defaultmateriallibrary/rin_skeleton_newgeo.actor\"\nCreateActorInstance -actorID %LASTRESULT% -xPos 0.000000 -yPos 0.000000 -zPos 0.000000 -xScale 1.000000 -yScale 1.000000 -zScale 1.000000 -rot 0.00000000,0.00000000,0.00000000,1.00000000\nLoadMotionSet -filename \"@assets@/Levels/Physics/C15096734_PhysxMaterials_DefaultMaterialLibrary/custom_motionset.motionset\"\nLoadAnimGraph -filename \"@assets@/Levels/Physics/C15096734_PhysxMaterials_DefaultMaterialLibrary/rin_physics.animgraph\"\n" +startScript="ImportActor -filename \"@products@/levels/physics/c15096734_physxmaterials_defaultmateriallibrary/rin_skeleton_newgeo.actor\"\nCreateActorInstance -actorID %LASTRESULT% -xPos 0.000000 -yPos 0.000000 -zPos 0.000000 -xScale 1.000000 -yScale 1.000000 -zScale 1.000000 -rot 0.00000000,0.00000000,0.00000000,1.00000000\nLoadMotionSet -filename \"@products@/levels/physics/c15096734_physxmaterials_defaultmateriallibrary/custom_motionset.motionset\"\nLoadAnimGraph -filename \"@products@/levels/physics/c15096734_physxmaterials_defaultmateriallibrary/rin_physics.animgraph\"\n" diff --git a/Code/Editor/Controls/FolderTreeCtrl.cpp b/Code/Editor/Controls/FolderTreeCtrl.cpp index b1cbb9414e..4088ab976f 100644 --- a/Code/Editor/Controls/FolderTreeCtrl.cpp +++ b/Code/Editor/Controls/FolderTreeCtrl.cpp @@ -278,17 +278,16 @@ void CFolderTreeCtrl::LoadTreeRec(const QString& currentFolder) void CFolderTreeCtrl::AddItem(const QString& path) { - QString folder; - QString fileNameWithoutExtension; - QString ext; - - Path::Split(path, folder, fileNameWithoutExtension, ext); + AZ::IO::FixedMaxPath folder{ AZ::IO::PathView(path.toUtf8().constData()) }; + AZ::IO::FixedMaxPath fileNameWithoutExtension = folder.Extension(); + folder = folder.ParentPath(); auto regex = QRegExp(m_fileNameSpec, Qt::CaseInsensitive, QRegExp::Wildcard); if (regex.exactMatch(path)) { - CTreeItem* folderTreeItem = CreateFolderItems(folder); - folderTreeItem->AddChild(fileNameWithoutExtension, path, eTreeImage_File); + CTreeItem* folderTreeItem = CreateFolderItems(QString::fromUtf8(folder.c_str(), static_cast(folder.Native().size()))); + folderTreeItem->AddChild(QString::fromUtf8(fileNameWithoutExtension.c_str(), + static_cast(fileNameWithoutExtension.Native().size())), path, eTreeImage_File); } } diff --git a/Code/Editor/Core/Tests/test_Main.cpp b/Code/Editor/Core/Tests/test_Main.cpp index 3d3e286f18..16b0aa92cf 100644 --- a/Code/Editor/Core/Tests/test_Main.cpp +++ b/Code/Editor/Core/Tests/test_Main.cpp @@ -33,6 +33,7 @@ public: protected: void SetupEnvironment() override { + AttachEditorCoreAZEnvironment(AZ::Environment::GetInstance()); m_allocatorScope.ActivateAllocators(); m_cryPak = new NiceMock(); @@ -49,6 +50,7 @@ protected: { delete m_cryPak; m_allocatorScope.DeactivateAllocators(); + DetachEditorCoreAZEnvironment(); } private: diff --git a/Code/Editor/Core/Tests/test_PathUtil.cpp b/Code/Editor/Core/Tests/test_PathUtil.cpp index 83e50a5947..cade19eb81 100644 --- a/Code/Editor/Core/Tests/test_PathUtil.cpp +++ b/Code/Editor/Core/Tests/test_PathUtil.cpp @@ -5,22 +5,29 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ -#include "EditorDefs.h" -#include -#include "Util/PathUtil.h" -#include - -TEST(PathUtil, GamePathToFullPath_DoesNotBufferOverflow) +#include +#include +namespace UnitTest { - // There are no test assertions in this test because the purpose is just to verify that the test runs without crashing - QString pngExtension(".png"); + class PathUtil + : public ScopedAllocatorSetupFixture + { + }; - // Create a string of lenth AZ_MAX_PATH_LEN that ends in .png - QString longStringMaxPath(AZ_MAX_PATH_LEN, 'x'); - longStringMaxPath.replace(longStringMaxPath.length() - pngExtension.length(), longStringMaxPath.length(), pngExtension); - Path::GamePathToFullPath(longStringMaxPath); + TEST_F(PathUtil, GamePathToFullPath_DoesNotBufferOverflow) + { + // There are no test assertions in this test because the purpose is just to verify that the test runs without crashing + QString pngExtension(".png"); - QString longStringMaxPathPlusOne(AZ_MAX_PATH_LEN + 1, 'x'); - longStringMaxPathPlusOne.replace(longStringMaxPathPlusOne.length() - pngExtension.length(), longStringMaxPathPlusOne.length(), pngExtension); - Path::GamePathToFullPath(longStringMaxPathPlusOne); + // Create a string of length AZ_MAX_PATH_LEN that ends in .png + QString longStringMaxPath(AZ_MAX_PATH_LEN, 'x'); + longStringMaxPath.replace(longStringMaxPath.length() - pngExtension.length(), longStringMaxPath.length(), pngExtension); + AZ_TEST_START_TRACE_SUPPRESSION; + Path::GamePathToFullPath(longStringMaxPath); + AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; + + QString longStringMaxPathPlusOne(AZ_MAX_PATH_LEN + 1, 'x'); + longStringMaxPathPlusOne.replace(longStringMaxPathPlusOne.length() - pngExtension.length(), longStringMaxPathPlusOne.length(), pngExtension); + Path::GamePathToFullPath(longStringMaxPathPlusOne); + } } diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp index b5eb4229df..4aa3d22114 100644 --- a/Code/Editor/CryEdit.cpp +++ b/Code/Editor/CryEdit.cpp @@ -2642,7 +2642,7 @@ void CCryEditApp::OnFileResaveSlices() sliceAssetInfos.reserve(5000); AZ::Data::AssetCatalogRequests::AssetEnumerationCB sliceCountCb = [&sliceAssetInfos]([[maybe_unused]] const AZ::Data::AssetId id, const AZ::Data::AssetInfo& info) { - // Only add slices and nothing that has been temporarily added to the catalog with a macro in it (ie @devroot@) + // Only add slices and nothing that has been temporarily added to the catalog with a macro in it (ie @engroot@) if (info.m_assetType == azrtti_typeid() && info.m_relativePath[0] != '@') { sliceAssetInfos.push_back(info); diff --git a/Code/Editor/CryEditDoc.cpp b/Code/Editor/CryEditDoc.cpp index 07d946c609..75bd0ad270 100644 --- a/Code/Editor/CryEditDoc.cpp +++ b/Code/Editor/CryEditDoc.cpp @@ -1108,7 +1108,7 @@ bool CCryEditDoc::SaveLevel(const QString& filename) if (QFileInfo(filename).isRelative()) { // Resolving the path through resolvepath would normalize and lowcase it, and in this case, we don't want that. - fullPathName = Path::ToUnixPath(QDir(QString::fromUtf8(gEnv->pFileIO->GetAlias("@devassets@"))).absoluteFilePath(fullPathName)); + fullPathName = Path::ToUnixPath(QDir(QString::fromUtf8(gEnv->pFileIO->GetAlias("@projectroot@"))).absoluteFilePath(fullPathName)); } if (!CFileUtil::OverwriteFile(fullPathName)) @@ -2159,7 +2159,7 @@ bool CCryEditDoc::LoadXmlArchiveArray(TDocMultiArchive& arrXmlAr, const QString& xmlAr.bLoading = true; // bound to the level folder, as if it were the assets folder. - // this mounts (whateverlevelname.ly) as @assets@/Levels/whateverlevelname/ and thus it works... + // this mounts (whateverlevelname.ly) as @products@/Levels/whateverlevelname/ and thus it works... bool openLevelPakFileSuccess = pIPak->OpenPack(levelPath.toUtf8().data(), absoluteLevelPath.toUtf8().data()); if (!openLevelPakFileSuccess) { diff --git a/Code/Editor/Dialogs/PythonScriptsDialog.cpp b/Code/Editor/Dialogs/PythonScriptsDialog.cpp index e95fb90c0a..35047947ac 100644 --- a/Code/Editor/Dialogs/PythonScriptsDialog.cpp +++ b/Code/Editor/Dialogs/PythonScriptsDialog.cpp @@ -91,7 +91,7 @@ CPythonScriptsDialog::CPythonScriptsDialog(QWidget* parent) { AZ::IO::Path newSourcePath = jsonSourcePathPointer; // Resolve any file aliases first - Do not use ResolvePath() as that assumes - // any relative path is underneath the @assets@ alias + // any relative path is underneath the @products@ alias if (auto fileIoBase = AZ::IO::FileIOBase::GetInstance(); fileIoBase != nullptr) { AZ::IO::FixedMaxPath replacedAliasPath; diff --git a/Code/Editor/EditorFileMonitor.cpp b/Code/Editor/EditorFileMonitor.cpp index 7feb9d32a8..311c42befa 100644 --- a/Code/Editor/EditorFileMonitor.cpp +++ b/Code/Editor/EditorFileMonitor.cpp @@ -14,6 +14,8 @@ // Editor #include "CryEdit.h" +#include + ////////////////////////////////////////////////////////////////////////// CEditorFileMonitor::CEditorFileMonitor() { @@ -177,26 +179,14 @@ void CEditorFileMonitor::OnFileMonitorChange(const SFileChangeInfo& rChange) // Make file relative to PrimaryCD folder. QString filename = rChange.filename; - // Remove game directory if present in path. - const QString rootPath = - QDir::fromNativeSeparators(QString::fromLatin1(Path::GetEditingRootFolder().c_str())); - if (filename.startsWith(rootPath, Qt::CaseInsensitive)) - { - filename = filename.right(filename.length() - rootPath.length()); - } + // Make path relative to the the project directory + AZ::IO::Path projectPath{ AZ::Utils::GetProjectPath() }; + AZ::IO::FixedMaxPath projectRelativeFilePath = AZ::IO::PathView(filename.toUtf8().constData()).LexicallyProximate( + projectPath); - // Make sure there is no leading slash - if (!filename.isEmpty() && (filename[0] == '\\' || filename[0] == '/')) + if (!projectRelativeFilePath.empty()) { - filename = filename.mid(1); - } - - if (!filename.isEmpty()) - { - //remove game name. Make it relative to the game folder - const QString filenameRelGame = RemoveGameName(filename); - const int extIndex = filename.lastIndexOf('.'); - const QString ext = filename.right(filename.length() - 1 - extIndex); + AZ::IO::PathView ext = projectRelativeFilePath.Extension(); // Check for File Monitor callback std::vector::iterator iter; @@ -207,15 +197,11 @@ void CEditorFileMonitor::OnFileMonitorChange(const SFileChangeInfo& rChange) // We compare against length of callback string, so we get directory matches as well as full filenames if (sCallback.pListener) { - if (sCallback.extension == "*" || ext.compare(sCallback.extension, Qt::CaseInsensitive) == 0) + if (sCallback.extension == "*" || AZ::IO::PathView(sCallback.extension.toUtf8().constData()) == ext) { - if (filenameRelGame.compare(sCallback.item, Qt::CaseInsensitive) == 0) + if (AZ::IO::PathView(sCallback.item.toUtf8().constData()) == projectRelativeFilePath) { - sCallback.pListener->OnFileChange(qPrintable(filenameRelGame), IFileChangeListener::EChangeType(rChange.changeType)); - } - else if (filename.compare(sCallback.item, Qt::CaseInsensitive) == 0) - { - sCallback.pListener->OnFileChange(qPrintable(filename), IFileChangeListener::EChangeType(rChange.changeType)); + sCallback.pListener->OnFileChange(qPrintable(projectRelativeFilePath.c_str()), IFileChangeListener::EChangeType(rChange.changeType)); } } } diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp index b9e4878879..41e950a058 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp @@ -1895,7 +1895,7 @@ void SandboxIntegrationManager::MakeSliceFromEntities(const AzToolsFramework::En AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(entitiesAndDescendants, &AzToolsFramework::ToolsApplicationRequestBus::Events::GatherEntitiesAndAllDescendents, entities); - const AZStd::string slicesAssetsPath = "@devassets@/Slices"; + const AZStd::string slicesAssetsPath = "@projectroot@/Slices"; if (!gEnv->pFileIO->Exists(slicesAssetsPath.c_str())) { diff --git a/Code/Editor/Plugins/EditorAssetImporter/AssetImporterWindow.cpp b/Code/Editor/Plugins/EditorAssetImporter/AssetImporterWindow.cpp index 98bf228391..0ff9467f33 100644 --- a/Code/Editor/Plugins/EditorAssetImporter/AssetImporterWindow.cpp +++ b/Code/Editor/Plugins/EditorAssetImporter/AssetImporterWindow.cpp @@ -30,6 +30,7 @@ class CXTPDockingPaneLayout; // Needed for settings.h #include #include #include +#include #include #include #include @@ -47,41 +48,6 @@ class CXTPDockingPaneLayout; // Needed for settings.h const char* AssetImporterWindow::s_documentationWebAddress = "http://docs.aws.amazon.com/lumberyard/latest/userguide/char-fbx-importer.html"; const AZ::Uuid AssetImporterWindow::s_browseTag = AZ::Uuid::CreateString("{C240D2E1-BFD2-4FFA-BB5B-CC0FA389A5D3}"); -void MakeUserFriendlySourceAssetPath(QString& out, const QString& sourcePath) -{ - char devAssetsRoot[AZ_MAX_PATH_LEN] = { 0 }; - if (!gEnv->pFileIO->ResolvePath("@devroot@", devAssetsRoot, AZ_MAX_PATH_LEN)) - { - out = sourcePath; - return; - } - - AZStd::replace(devAssetsRoot, devAssetsRoot + AZ_MAX_PATH_LEN- 1, AZ_WRONG_FILESYSTEM_SEPARATOR, AZ_CORRECT_FILESYSTEM_SEPARATOR); - - // Find if the sourcePathArray is a sub directory of the devAssets folder - // Keep reference to sourcePathArray long enough to use in PathView - QByteArray sourcePathArray = sourcePath.toUtf8(); - AZ::IO::PathView sourcePathRootView(sourcePathArray.data()); - AZ::IO::PathView devAssetsRootView(devAssetsRoot); - auto [sourcePathIter, devAssetsIter] = AZStd::mismatch(sourcePathRootView.begin(), sourcePathRootView.end(), - devAssetsRootView.begin(), devAssetsRootView.end()); - // If the devAssets path iterator is not equal to the end, then there was a mismistch while comparing it - // against the source path indicating that the source path is not a sub-directory - if (devAssetsIter != devAssetsRootView.end()) - { - out = sourcePath; - return; - } - - int offset = aznumeric_cast(strlen(devAssetsRoot)); - if (sourcePath.at(offset) == AZ_CORRECT_FILESYSTEM_SEPARATOR) - { - ++offset; - } - out = sourcePath.right(sourcePath.length() - offset); - -} - AssetImporterWindow::AssetImporterWindow() : AssetImporterWindow(nullptr) { @@ -102,7 +68,7 @@ AssetImporterWindow::AssetImporterWindow(QWidget* parent) AssetImporterWindow::~AssetImporterWindow() { - AZ_Assert(m_processingOverlayIndex == AZ::SceneAPI::UI::OverlayWidget::s_invalidOverlayIndex, + AZ_Assert(m_processingOverlayIndex == AZ::SceneAPI::UI::OverlayWidget::s_invalidOverlayIndex, "Processing overlay (and potentially background thread) still active at destruction."); AZ_Assert(!m_processingOverlay, "Processing overlay (and potentially background thread) still active at destruction."); } @@ -133,7 +99,7 @@ void AssetImporterWindow::OpenFile(const AZStd::string& filePath) QMessageBox::warning(this, "In progress", "Unable to close one or more windows at this time."); return; } - + OpenFileInternal(filePath); } @@ -146,7 +112,7 @@ void AssetImporterWindow::closeEvent(QCloseEvent* ev) if (m_processingOverlay) { - AZ_Assert(m_processingOverlayIndex != AZ::SceneAPI::UI::OverlayWidget::s_invalidOverlayIndex, + AZ_Assert(m_processingOverlayIndex != AZ::SceneAPI::UI::OverlayWidget::s_invalidOverlayIndex, "Processing overlay present, but not the index in the overlay for it."); if (m_processingOverlay->HasProcessingCompleted()) { @@ -157,7 +123,7 @@ void AssetImporterWindow::closeEvent(QCloseEvent* ev) } else { - QMessageBox::critical(this, "Processing In Progress", "Unable to close the result window at this time.", + QMessageBox::critical(this, "Processing In Progress", "Unable to close the result window at this time.", QMessageBox::Ok, QMessageBox::Ok); ev->ignore(); return; @@ -165,7 +131,7 @@ void AssetImporterWindow::closeEvent(QCloseEvent* ev) } else { - QMessageBox::critical(this, "Processing In Progress", "Please wait until processing has completed to try again.", + QMessageBox::critical(this, "Processing In Progress", "Please wait until processing has completed to try again.", QMessageBox::Ok, QMessageBox::Ok); ev->ignore(); return; @@ -199,7 +165,9 @@ void AssetImporterWindow::Init() // Load the style sheets AzQtComponents::StylesheetPreprocessor styleSheetProcessor(nullptr); - AZStd::string mainWindowQSSPath = Path::GetEditingRootFolder() + "\\Editor\\Styles\\AssetImporterWindow.qss"; + auto mainWindowQSSPath = AZ::IO::Path(AZ::Utils::GetEnginePath()) / "Assets"; + mainWindowQSSPath /= "Editor/Styles/AssetImporterWindow.qss"; + mainWindowQSSPath.MakePreferred(); QFile mainWindowStyleSheetFile(mainWindowQSSPath.c_str()); if (mainWindowStyleSheetFile.open(QFile::ReadOnly)) { @@ -212,7 +180,7 @@ void AssetImporterWindow::Init() { ui->m_actionInspect->setVisible(false); } - + ResetMenuAccess(WindowState::InitialNothingLoaded); // Setup the overlay system, and set the root to be the root display. The root display has the browse, @@ -220,7 +188,7 @@ void AssetImporterWindow::Init() m_overlay.reset(aznew AZ::SceneAPI::UI::OverlayWidget(this)); m_rootDisplay.reset(aznew ImporterRootDisplay(m_serializeContext)); connect(m_rootDisplay.data(), &ImporterRootDisplay::UpdateClicked, this, &AssetImporterWindow::UpdateClicked); - + connect(m_overlay.data(), &AZ::SceneAPI::UI::OverlayWidget::LayerAdded, this, &AssetImporterWindow::OverlayLayerAdded); connect(m_overlay.data(), &AZ::SceneAPI::UI::OverlayWidget::LayerRemoved, this, &AssetImporterWindow::OverlayLayerRemoved); @@ -242,7 +210,7 @@ void AssetImporterWindow::Init() AZStd::string joinedExtensions; AzFramework::StringFunc::Join(joinedExtensions, extensions.begin(), extensions.end(), " or "); - AZStd::string firstLineText = + AZStd::string firstLineText = AZStd::string::format( "%s files are available for use after placing them in any folder within your game project. " "These files will automatically be processed and may be accessed via the Asset Browser. Learn more...", @@ -250,13 +218,13 @@ void AssetImporterWindow::Init() ui->m_initialPromptFirstLine->setText(firstLineText.c_str()); - AZStd::string secondLineText = + AZStd::string secondLineText = AZStd::string::format("To adjust the %s settings, right-click the file in the Asset Browser and select \"Edit Settings\" from the context menu.", joinedExtensions.c_str()); ui->m_initialPromptSecondLine->setText(secondLineText.c_str()); } else { - AZStd::string firstLineText = + AZStd::string firstLineText = AZStd::string::format( "Files are available for use after placing them in any folder within your game project. " "These files will automatically be processed and may be accessed via the Asset Browser. Learn more...", s_documentationWebAddress); @@ -282,12 +250,12 @@ void AssetImporterWindow::OpenFileInternal(const AZStd::string& filePath) auto asyncLoadHandler = AZStd::make_shared( s_browseTag, [this, filePath]() - { - m_assetImporterDocument->LoadScene(filePath); + { + m_assetImporterDocument->LoadScene(filePath); }, [this]() { - HandleAssetLoadingCompleted(); + HandleAssetLoadingCompleted(); }, this); m_processingOverlay.reset(new ProcessingOverlayWidget(m_overlay.data(), ProcessingOverlayWidget::Layout::Loading, s_browseTag)); @@ -304,7 +272,7 @@ bool AssetImporterWindow::IsAllowedToChangeSourceFile() return true; } - QMessageBox messageBox(QMessageBox::Icon::NoIcon, "Unsaved changes", + QMessageBox messageBox(QMessageBox::Icon::NoIcon, "Unsaved changes", "You have unsaved changes. Do you want to discard those changes?", QMessageBox::StandardButton::Discard | QMessageBox::StandardButton::Cancel, this); messageBox.exec(); @@ -406,7 +374,7 @@ void AssetImporterWindow::OnSceneResetRequested() else { m_assetImporterDocument->ClearScene(); - AZ_TracePrintf(ErrorWindow, "Manifest reset returned in '%s'", + AZ_TracePrintf(ErrorWindow, "Manifest reset returned in '%s'", result.GetResult() == ProcessingResult::Failure ? "Failure" : "Ignored"); } }, @@ -456,7 +424,7 @@ void AssetImporterWindow::OnInspect() // make sure the inspector doesn't outlive the AssetImporterWindow, since we own the data it will be inspecting. auto* theInspectWidget = aznew AZ::SceneAPI::UI::SceneGraphInspectWidget(*m_assetImporterDocument->GetScene()); QObject::connect(this, &QObject::destroyed, theInspectWidget, [theInspectWidget]() { theInspectWidget->window()->close(); } ); - + m_overlay->PushLayer(label, theInspectWidget, "Scene Inspector", buttons); } @@ -483,7 +451,7 @@ void AssetImporterWindow::OverlayLayerRemoved() else { ResetMenuAccess(WindowState::InitialNothingLoaded); - + ui->m_initialBrowseContainer->show(); m_rootDisplay->hide(); } @@ -533,8 +501,9 @@ void AssetImporterWindow::HandleAssetLoadingCompleted() m_fullSourcePath = m_assetImporterDocument->GetScene()->GetSourceFilename(); SetTitle(m_fullSourcePath.c_str()); - QString userFriendlyFileName; - MakeUserFriendlySourceAssetPath(userFriendlyFileName, m_fullSourcePath.c_str()); + AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath(); + AZ::IO::FixedMaxPath relativeSourcePath = AZ::IO::PathView(m_fullSourcePath).LexicallyProximate(projectPath); + auto userFriendlyFileName = QString::fromUtf8(relativeSourcePath.c_str(), static_cast(relativeSourcePath.Native().size())); m_rootDisplay->SetSceneDisplay(userFriendlyFileName, m_assetImporterDocument->GetScene()); // Once we've browsed to something successfully, we need to hide the initial browse button layer and diff --git a/Code/Editor/Plugins/EditorAssetImporter/SceneSerializationHandler.cpp b/Code/Editor/Plugins/EditorAssetImporter/SceneSerializationHandler.cpp index b1d07af41c..5ee54667b9 100644 --- a/Code/Editor/Plugins/EditorAssetImporter/SceneSerializationHandler.cpp +++ b/Code/Editor/Plugins/EditorAssetImporter/SceneSerializationHandler.cpp @@ -7,9 +7,11 @@ */ #include +#include #include #include #include +#include #include #include #include @@ -50,22 +52,15 @@ namespace AZ return nullptr; } - AZStd::string cleanPath = filePath; - if (AzFramework::StringFunc::Path::IsRelative(filePath.c_str())) + AZ::IO::Path enginePath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) { - const char* absolutePath = nullptr; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(absolutePath, - &AzToolsFramework::AssetSystemRequestBus::Events::GetAbsoluteDevRootFolderPath); - AZ_Assert(absolutePath, "Unable to retrieve the dev folder path"); - AzFramework::StringFunc::Path::Join(absolutePath, cleanPath.c_str(), cleanPath); - } - else - { - // Normalizing is not needed if the path is relative as Join(...) will also normalize. - AzFramework::StringFunc::Path::Normalize(cleanPath); + settingsRegistry->Get(enginePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); } - auto sceneIt = m_scenes.find(cleanPath); + AZ::IO::Path cleanPath = (enginePath / filePath).LexicallyNormal(); + + auto sceneIt = m_scenes.find(cleanPath.Native()); if (sceneIt != m_scenes.end()) { AZStd::shared_ptr scene = sceneIt->second.lock(); @@ -98,14 +93,14 @@ namespace AZ } AZStd::shared_ptr scene = - AssetImportRequest::LoadSceneFromVerifiedPath(cleanPath, sceneSourceGuid, AssetImportRequest::RequestingApplication::Editor, SceneAPI::SceneCore::LoadingComponent::TYPEINFO_Uuid()); + AssetImportRequest::LoadSceneFromVerifiedPath(cleanPath.Native(), sceneSourceGuid, AssetImportRequest::RequestingApplication::Editor, SceneAPI::SceneCore::LoadingComponent::TYPEINFO_Uuid()); if (!scene) { AZ_TracePrintf(Utilities::ErrorWindow, "Failed to load the requested scene."); return nullptr; } - m_scenes.emplace(AZStd::move(cleanPath), scene); + m_scenes.emplace(AZStd::move(cleanPath.Native()), scene); return scene; } diff --git a/Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsToolWindow.cpp b/Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsToolWindow.cpp index 6b454474be..a53ce966c4 100644 --- a/Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsToolWindow.cpp +++ b/Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsToolWindow.cpp @@ -46,7 +46,6 @@ namespace ProjectSettingsTool , LastPathBus::Handler() , m_ui(new Ui::ProjectSettingsToolWidget()) , m_reconfigureProcess() - , m_devRoot(GetDevRoot()) , m_projectRoot(GetProjectRoot()) , m_projectName(GetProjectName()) , m_plistsInitVector( diff --git a/Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsToolWindow.h b/Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsToolWindow.h index 1c9aa4b1bf..daa5bea27c 100644 --- a/Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsToolWindow.h +++ b/Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsToolWindow.h @@ -147,7 +147,6 @@ namespace ProjectSettingsTool // The process used to reconfigure settings QProcess m_reconfigureProcess; - AZStd::string m_devRoot; AZStd::string m_projectRoot; AZStd::string m_projectName; diff --git a/Code/Editor/Plugins/ProjectSettingsTool/Utils.cpp b/Code/Editor/Plugins/ProjectSettingsTool/Utils.cpp index 0e171adf04..d5b94469cc 100644 --- a/Code/Editor/Plugins/ProjectSettingsTool/Utils.cpp +++ b/Code/Editor/Plugins/ProjectSettingsTool/Utils.cpp @@ -27,37 +27,31 @@ namespace } template - StringType GetAbsoluteDevRoot() + StringType GetAbsoluteEngineRoot() { - const char* devRoot = nullptr; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult( - devRoot, - &AzToolsFramework::AssetSystemRequestBus::Handler::GetAbsoluteDevRootFolderPath); + AZ::IO::FixedMaxPath engineRoot = AZ::Utils::GetEnginePath(); - if (!devRoot) + if (engineRoot.empty()) { return ""; } - StringType devRootString(devRoot); - ToUnixPath(devRootString); - return devRootString; + StringType engineRootString(engineRoot.c_str()); + ToUnixPath(engineRootString); + return engineRootString; } template StringType GetAbsoluteProjectRoot() { - const char* projectRoot = nullptr; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult( - projectRoot, - &AzToolsFramework::AssetSystemRequestBus::Handler::GetAbsoluteDevGameFolderPath); + AZ::IO::FixedMaxPath projectRoot = AZ::Utils::GetProjectPath(); - if (!projectRoot) + if (projectRoot.empty()) { return ""; } - StringType projectRootString(projectRoot); + StringType projectRootString(projectRoot.c_str()); ToUnixPath(projectRootString); return projectRootString; } @@ -87,9 +81,9 @@ namespace ProjectSettingsTool return reinterpret_cast(func); } - AZStd::string GetDevRoot() + AZStd::string GetEngineRoot() { - return GetAbsoluteDevRoot(); + return GetAbsoluteEngineRoot(); } AZStd::string GetProjectRoot() { @@ -104,7 +98,7 @@ namespace ProjectSettingsTool QString SelectXmlFromFileDialog(const QString& currentFile) { // The selected file must be relative to this path - QString defaultPath = GetAbsoluteDevRoot(); + QString defaultPath = GetAbsoluteEngineRoot(); QString startPath; // Choose the starting path for file dialog @@ -139,7 +133,7 @@ namespace ProjectSettingsTool QString SelectImageFromFileDialog(const QString& currentFile) { - QString defaultPath = QStringLiteral("%1Code%2/Resources/").arg(GetAbsoluteDevRoot(), ::GetProjectName()); + QString defaultPath = QStringLiteral("%1Code%2/Resources/").arg(GetAbsoluteEngineRoot(), ::GetProjectName()); QString startPath; @@ -188,7 +182,7 @@ namespace ProjectSettingsTool // Android if (group <= ImageGroup::AndroidPortrait) { - root = GetDevRoot() + "/Code/Tools/Android/ProjectBuilder/app_"; + root = GetEngineRoot() + "/Code/Tools/Android/ProjectBuilder/app_"; } //Ios else diff --git a/Code/Editor/Plugins/ProjectSettingsTool/Utils.h b/Code/Editor/Plugins/ProjectSettingsTool/Utils.h index 4226d534a6..050fb3b85b 100644 --- a/Code/Editor/Plugins/ProjectSettingsTool/Utils.h +++ b/Code/Editor/Plugins/ProjectSettingsTool/Utils.h @@ -17,7 +17,7 @@ namespace ProjectSettingsTool { void* ConvertFunctorToVoid(AZStd::pair(*func)(const QString&)); - AZStd::string GetDevRoot(); + AZStd::string GetEngineRoot(); AZStd::string GetProjectRoot(); AZStd::string GetProjectName(); diff --git a/Code/Editor/Settings.cpp b/Code/Editor/Settings.cpp index 05a6960695..47743d1c42 100644 --- a/Code/Editor/Settings.cpp +++ b/Code/Editor/Settings.cpp @@ -935,8 +935,9 @@ void SEditorSettings::LoadDefaultGamePaths() searchPaths[EDITOR_PATH_MATERIALS].push_back((Path::GetEditingGameDataFolder() + "/Materials").c_str()); } - AZStd::string iconsPath; - AZ::StringFunc::Path::Join(Path::GetEditingRootFolder().c_str(), "Editor/UI/Icons", iconsPath); + auto iconsPath = AZ::IO::Path(AZ::Utils::GetEnginePath()) / "Assets"; + iconsPath /= "Editor/UI/Icons"; + iconsPath.MakePreferred(); searchPaths[EDITOR_PATH_UI_ICONS].push_back(iconsPath.c_str()); } diff --git a/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp b/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp index b510315995..d7901e338a 100644 --- a/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp +++ b/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp @@ -269,7 +269,7 @@ void CSequenceBatchRenderDialog::OnRenderItemSelChange() // Enable/disable the 'remove'/'update' button properly. bool bNoSelection = !m_ui->m_renderList->selectionModel()->hasSelection(); m_ui->BATCH_RENDER_REMOVE_SEQ->setEnabled(bNoSelection ? false : true); - + CheckForEnableUpdateButton(); if (bNoSelection) @@ -360,7 +360,7 @@ void CSequenceBatchRenderDialog::OnRenderItemSelChange() cvarsText += item.cvars[static_cast(i)]; cvarsText += "\r\n"; } - m_ui->m_cvarsEdit->setPlainText(cvarsText); + m_ui->m_cvarsEdit->setPlainText(cvarsText); } void CSequenceBatchRenderDialog::CheckForEnableUpdateButton() @@ -494,7 +494,7 @@ void CSequenceBatchRenderDialog::OnSavePreset() } void CSequenceBatchRenderDialog::stashActiveViewportResolution() -{ +{ // stash active resolution in global vars activeViewportWidth = resolutions[0][0]; activeViewportHeight = resolutions[0][1]; @@ -502,7 +502,7 @@ void CSequenceBatchRenderDialog::stashActiveViewportResolution() if (activeViewport) { activeViewport->GetDimensions(&activeViewportWidth, &activeViewportHeight); - } + } } void CSequenceBatchRenderDialog::OnGo() @@ -640,7 +640,7 @@ void CSequenceBatchRenderDialog::OnResolutionSelected() int defaultH; const QString currentCustomResText = m_ui->m_resolutionCombo->currentText(); GetResolutionFromCustomResText(currentCustomResText.toStdString().c_str(), defaultW, defaultH); - + CCustomResolutionDlg resDlg(defaultW, defaultH, this); if (resDlg.exec() == QDialog::Accepted) { @@ -752,7 +752,7 @@ bool CSequenceBatchRenderDialog::LoadOutputOptions(const QString& pathname) { const QString customResText = resolutionNode->getContent(); m_ui->m_resolutionCombo->setItemText(curSel, customResText); - + GetResolutionFromCustomResText(customResText.toStdString().c_str(), m_customResW, m_customResH); } m_ui->m_resolutionCombo->setCurrentIndex(curSel); @@ -907,12 +907,12 @@ void CSequenceBatchRenderDialog::CaptureItemStart() folder += "/"; folder += itemText; - // If this is a relative path, prepend the @assets@ folder to match where the Renderer is going + // If this is a relative path, prepend the @products@ folder to match where the Renderer is going // to dump the frame buffer image captures. if (AzFramework::StringFunc::Path::IsRelative(folder.toUtf8().data())) { AZStd::string absolutePath; - AZStd::string assetsRoot = AZ::IO::FileIOBase::GetInstance()->GetAlias("@assets@"); + AZStd::string assetsRoot = AZ::IO::FileIOBase::GetInstance()->GetAlias("@products@"); AzFramework::StringFunc::Path::Join(assetsRoot.c_str(), folder.toUtf8().data(), absolutePath); folder = absolutePath.c_str(); } @@ -962,7 +962,7 @@ void CSequenceBatchRenderDialog::CaptureItemStart() m_renderContext.cvarDisplayInfoBU = cvarDebugInfo->GetIVal(); if (renderItem.disableDebugInfo && cvarDebugInfo->GetIVal()) { - const int DISPLAY_INFO_OFF = 0; + const int DISPLAY_INFO_OFF = 0; cvarDebugInfo->Set(DISPLAY_INFO_OFF); } } @@ -1100,13 +1100,13 @@ void CSequenceBatchRenderDialog::OnUpdateEnd(IAnimSequence* sequence) sequence->SetActiveDirector(m_renderContext.pActiveDirectorBU); const auto imageFormat = m_ui->m_imageFormatCombo->currentText(); - + SRenderItem renderItem = m_renderItems[m_renderContext.currentItemIndex]; if (m_bFFMPEGCommandAvailable && renderItem.bCreateVideo) { // Create a video using the ffmpeg plug-in from captured images. m_renderContext.processingFFMPEG = true; - + AZStd::string outputFolder = m_renderContext.captureOptions.folder; auto future = QtConcurrent::run( [renderItem, outputFolder, imageFormat] @@ -1238,7 +1238,7 @@ void CSequenceBatchRenderDialog::OnKickIdleTimout() } void CSequenceBatchRenderDialog::OnKickIdle() -{ +{ if (m_renderContext.captureState == CaptureState::WarmingUpAfterResChange) { OnUpdateWarmingUpAfterResChange(); @@ -1254,7 +1254,7 @@ void CSequenceBatchRenderDialog::OnKickIdle() else if (m_renderContext.captureState == CaptureState::Capturing) { OnUpdateCapturing(); - } + } else if (m_renderContext.captureState == CaptureState::End) { OnUpdateEnd(m_renderContext.endingSequence); diff --git a/Code/Editor/Util/PathUtil.cpp b/Code/Editor/Util/PathUtil.cpp index c9e6823824..ca3481ddae 100644 --- a/Code/Editor/Util/PathUtil.cpp +++ b/Code/Editor/Util/PathUtil.cpp @@ -11,9 +11,9 @@ #include "PathUtil.h" -#include // for AZ_MAX_PATH_LEN +#include +#include #include // for ebus events -#include #include #include #include @@ -179,7 +179,7 @@ namespace Path EBUS_EVENT_RESULT(engineRoot, AzFramework::ApplicationRequests::Bus, GetEngineRoot); return QString(engineRoot); } - + ////////////////////////////////////////////////////////////////////////// QString& ReplaceFilename(const QString& strFilepath, const QString& strFilename, QString& strOutputFilename, bool bCallCaselessPath) { @@ -216,30 +216,21 @@ namespace Path ////////////////////////////////////////////////////////////////////////// QString GetResolvedUserSandboxFolder() { - char resolvedPath[AZ_MAX_PATH_LEN] = { 0 }; - gEnv->pFileIO->ResolvePath(GetUserSandboxFolder().toUtf8().data(), resolvedPath, AZ_MAX_PATH_LEN); - return QString::fromLatin1(resolvedPath); + AZ::IO::FixedMaxPath userSandboxFolderPath; + gEnv->pFileIO->ResolvePath(userSandboxFolderPath, GetUserSandboxFolder().toUtf8().constData()); + return QString::fromUtf8(userSandboxFolderPath.c_str(), static_cast(userSandboxFolderPath.Native().size())); } // internal function, you should use GetEditingGameDataFolder instead. AZStd::string GetGameAssetsFolder() { - const char* resultValue = nullptr; - EBUS_EVENT_RESULT(resultValue, AzToolsFramework::AssetSystemRequestBus, GetAbsoluteDevGameFolderPath); - if (!resultValue) + AZ::IO::Path projectPath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) { - if ((gEnv) && (gEnv->pFileIO)) - { - resultValue = gEnv->pFileIO->GetAlias("@devassets@"); - } + settingsRegistry->Get(projectPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath); } - if (!resultValue) - { - resultValue = "."; - } - - return resultValue; + return projectPath.Native(); } /// Get the data folder @@ -258,26 +249,6 @@ namespace Path return str; } - //! Get the root folder (in source control or other writable assets) where you should save root data. - AZStd::string GetEditingRootFolder() - { - const char* resultValue = nullptr; - EBUS_EVENT_RESULT(resultValue, AzToolsFramework::AssetSystemRequestBus, GetAbsoluteDevRootFolderPath); - - if (!resultValue) - { - if ((gEnv) && (gEnv->pFileIO)) - { - resultValue = gEnv->pFileIO->GetAlias("@devassets@"); - } - } - if (!resultValue) - { - resultValue = "."; - } - return resultValue; - } - AZStd::string MakeModPathFromGamePath(const char* relGamePath) { @@ -335,165 +306,60 @@ namespace Path return ""; } - bool relPathfound = false; + bool relPathFound = false; AZStd::string relativePath; AZStd::string fullAssetPath(fullPath.toUtf8().data()); - EBUS_EVENT_RESULT(relPathfound, AzToolsFramework::AssetSystemRequestBus, GetRelativeProductPathFromFullSourceOrProductPath, fullAssetPath, relativePath); + EBUS_EVENT_RESULT(relPathFound, AzToolsFramework::AssetSystemRequestBus, GetRelativeProductPathFromFullSourceOrProductPath, fullAssetPath, relativePath); - if (relPathfound) + if (relPathFound) { // do not normalize this path, it will already be an appropriate asset ID. return CaselessPaths(relativePath.c_str()); } - char rootpath[_MAX_PATH] = { 0 }; - azstrcpy(rootpath, _MAX_PATH, Path::GetEditingRootFolder().c_str()); - - if (bRelativeToGameFolder) - { - azstrcpy(rootpath, _MAX_PATH, Path::GetEditingGameDataFolder().c_str()); - } - - QString rootPathNormalized(rootpath); - QString srcPathNormalized(fullPath); - -#if defined(AZ_PLATFORM_WINDOWS) - // avoid confusing PathRelativePathTo - rootPathNormalized.replace('/', '\\'); - srcPathNormalized.replace('/', '\\'); -#endif + AZ::IO::FixedMaxPath rootPath = bRelativeToGameFolder ? AZ::Utils::GetProjectPath() : AZ::Utils::GetEnginePath(); + AZ::IO::FixedMaxPath resolvedFullPath; + AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(resolvedFullPath, fullPath.toUtf8().constData()); // Create relative path - char resolvedSrcPath[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(srcPathNormalized.toUtf8().data(), resolvedSrcPath, AZ_MAX_PATH_LEN); - QByteArray path = QDir(rootPathNormalized).relativeFilePath(resolvedSrcPath).toUtf8(); - if (path.isEmpty()) - { - return fullPath; - } - // The following code is required because the windows PathRelativePathTo function will always return "./SomePath" instead of just "SomePath" - // Only remove single dot (.) and slash parts of a path, never the double dot (..) - const char* pBuffer = path.data(); - bool bHasDot = false; - while (*pBuffer && pBuffer != path.end()) - { - switch (*pBuffer) - { - case '.': - if (bHasDot) - { - // Found a double dot, rewind and stop removing - pBuffer--; - break; - } - // Fall through intended - case '/': - case '\\': - bHasDot = (*pBuffer == '.'); - pBuffer++; - continue; - } - break; - } - - QString relPath = pBuffer; - return CaselessPaths(relPath); + return CaselessPaths(resolvedFullPath.LexicallyProximate(rootPath).MakePreferred().c_str()); } QString GamePathToFullPath(const QString& path) { using namespace AzToolsFramework; - AZ_Warning("GamePathToFullPath", path.size() <= AZ_MAX_PATH_LEN, "Path exceeds maximum path length of %d", AZ_MAX_PATH_LEN); - if ((gEnv) && (gEnv->pFileIO) && gEnv->pCryPak && path.size() <= AZ_MAX_PATH_LEN) + AZ_Warning("GamePathToFullPath", path.size() <= AZ::IO::MaxPathLength, "Path exceeds maximum path length of %zu", AZ::IO::MaxPathLength); + if (path.size() <= AZ::IO::MaxPathLength) { // first, adjust the file name for mods: - bool fullPathfound = false; - AZStd::string assetFullPath; - AZStd::string adjustedFilePath = path.toUtf8().data(); - AssetSystemRequestBus::BroadcastResult(fullPathfound, &AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, adjustedFilePath, assetFullPath); - if (fullPathfound) + bool fullPathFound = false; + AZ::IO::Path assetFullPath; + AZ::IO::Path adjustedFilePath = path.toUtf8().constData(); + AssetSystemRequestBus::BroadcastResult(fullPathFound, &AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, + adjustedFilePath.Native(), assetFullPath.Native()); + if (fullPathFound) { - //if the bus message succeeds than normalize and lowercase the path - AzFramework::StringFunc::Path::Normalize(assetFullPath); - return assetFullPath.c_str(); + //if the bus message succeeds than normalize + return assetFullPath.LexicallyNormal().c_str(); } - // if the bus message didn't succeed, 'guess' the source assets: + // if the bus message didn't succeed, check if he path exist as a resolved path else { // Not all systems have been converted to use local paths. Some editor files save XML files directly, and a full or correctly aliased path is already passed in. // If the path passed in exists already, then return the resolved filepath if (AZ::IO::FileIOBase::GetDirectInstance()->Exists(adjustedFilePath.c_str())) { - char resolvedPath[AZ_MAX_PATH_LEN + PathUtil::maxAliasLength] = { 0 }; - AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(adjustedFilePath.c_str(), resolvedPath, AZ_MAX_PATH_LEN + PathUtil::maxAliasLength); - return QString::fromUtf8(resolvedPath); + AZ::IO::FixedMaxPath resolvedPath; + AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(resolvedPath, adjustedFilePath); + return QString::fromUtf8(resolvedPath.c_str(), static_cast(resolvedPath.Native().size())); } - // if we get here it means that the Asset Processor does not know about this file. most of the time we should never get here - // the rest of this code just does a bunch of heuristic guesses in case of missing files or if the user has hand-edited - // the asset cache by moving files in via some other means or external process. - if (adjustedFilePath[0] != '@') - { - const char* prefix = (adjustedFilePath[0] == '/' || adjustedFilePath[0] == '\\') ? "@devassets@" : "@devassets@/"; - adjustedFilePath = prefix + adjustedFilePath; - } - - char szAdjustedFile[AZ_MAX_PATH_LEN + PathUtil::maxAliasLength] = { 0 }; - gEnv->pFileIO->ResolvePath(adjustedFilePath.c_str(), szAdjustedFile, AZ_ARRAY_SIZE(szAdjustedFile)); - - if ((azstrnicmp(szAdjustedFile, "@devassets@", 11) == 0) && ((szAdjustedFile[11] == '/') || (szAdjustedFile[11] == '\\'))) - { - if (!gEnv->pCryPak->IsFileExist(szAdjustedFile)) - { - AZStd::string newName(szAdjustedFile); - AzFramework::StringFunc::Replace(newName, "@devassets@", "@devroot@/engine", false); - - if (gEnv->pCryPak->IsFileExist(newName.c_str())) - { - azstrcpy(szAdjustedFile, AZ_ARRAY_SIZE(szAdjustedFile), newName.c_str()); - } - else - { - // getting tricky here, try @devroot@ alone, in case its 'editor' - AzFramework::StringFunc::Replace(newName, "@devassets@", "@devroot@", false); - if (gEnv->pCryPak->IsFileExist(szAdjustedFile)) - { - azstrcpy(szAdjustedFile, AZ_ARRAY_SIZE(szAdjustedFile), newName.c_str()); - } - // give up, best guess is just @devassets@ - } - } - } - - // we should very rarely actually get to this point in the code. - - // szAdjustedFile may contain an alias at this point. (@assets@/blah.whatever) - // there is a case in which the loose asset exists only within a pak file for some reason - // this is not recommended but it is possible.in that case, we want to return the original szAdjustedFile - // without touching it or resolving it so that crypak can open it successfully. - char adjustedPath[AZ_MAX_PATH_LEN + PathUtil::maxAliasLength] = { 0 }; - if (gEnv->pFileIO->ResolvePath(szAdjustedFile, adjustedPath, AZ_MAX_PATH_LEN + PathUtil::maxAliasLength)) // resolve to full path - { - if ((gEnv->pCryPak->IsFileExist(adjustedPath)) || (!gEnv->pCryPak->IsFileExist(szAdjustedFile))) - { - // note that if we get here, then EITHER - // the file exists as a loose asset in the actual adjusted path - // OR the file does not exist in the original passed-in aliased name (like '@assets@/whatever') - // in which case we may as well just resolve the path to a full path and return it. - assetFullPath = adjustedPath; - AzFramework::StringFunc::Path::Normalize(assetFullPath); - azstrcpy(szAdjustedFile, AZ_MAX_PATH_LEN + PathUtil::maxAliasLength, assetFullPath.c_str()); - } - // if the above case succeeded then it means that the file does NOT exist loose - // but DOES exist in a pak, in which case we leave szAdjustedFile with the alias on the front of it, meaning - // fopens via crypak will actually succeed. - } - return szAdjustedFile; + return path; } } else { - return ""; + return QString{}; } } diff --git a/Code/Editor/Util/PathUtil.h b/Code/Editor/Util/PathUtil.h index 2c49031155..163d74e358 100644 --- a/Code/Editor/Util/PathUtil.h +++ b/Code/Editor/Util/PathUtil.h @@ -44,9 +44,6 @@ namespace Path //! always returns a full path EDITOR_CORE_API AZStd::string GetEditingGameDataFolder(); - //! Get the root folder (in source control or other writable assets) where you should save root data. - EDITOR_CORE_API AZStd::string GetEditingRootFolder(); - //! Set the current mod NAME for editing purposes. After doing this the above functions will take this into account //! name only, please! EDITOR_CORE_API void SetModName(const char* input); @@ -69,93 +66,6 @@ namespace Path return strPath; } - //! Split full file name to path and filename - //! @param filepath [IN] Full file name inclusing path. - //! @param path [OUT] Extracted file path. - //! @param file [OUT] Extracted file (with extension). - inline void Split(const QString& filepath, QString& path, QString& file) - { - char path_buffer[_MAX_PATH]; - char drive[_MAX_DRIVE]; - char dir[_MAX_DIR]; - char fname[_MAX_FNAME]; - char ext[_MAX_EXT]; -#ifdef AZ_COMPILER_MSVC - _splitpath_s(filepath.toUtf8().data(), drive, AZ_ARRAY_SIZE(drive), dir, AZ_ARRAY_SIZE(dir), fname, AZ_ARRAY_SIZE(fname), ext, AZ_ARRAY_SIZE(ext)); - _makepath_s(path_buffer, AZ_ARRAY_SIZE(path_buffer), drive, dir, 0, 0); - path = path_buffer; - _makepath_s(path_buffer, AZ_ARRAY_SIZE(path_buffer), 0, 0, fname, ext); -#else - _splitpath(filepath.toUtf8().data(), drive, dir, fname, ext); - _makepath(path_buffer, drive, dir, 0, 0); - path = path_buffer; - _makepath(path_buffer, 0, 0, fname, ext); -#endif - file = path_buffer; - } - inline void Split(const AZStd::string& filepath, AZStd::string& path, AZStd::string& file) - { - char path_buffer[_MAX_PATH]; - char drive[_MAX_DRIVE]; - char dir[_MAX_DIR]; - char fname[_MAX_FNAME]; - char ext[_MAX_EXT]; -#ifdef AZ_COMPILER_MSVC - _splitpath_s(filepath.c_str(), drive, AZ_ARRAY_SIZE(drive), dir, AZ_ARRAY_SIZE(dir), 0, 0, 0, 0); - _makepath_s(path_buffer, AZ_ARRAY_SIZE(path_buffer), drive, dir, 0, 0); - path = path_buffer; - _makepath_s(path_buffer, AZ_ARRAY_SIZE(path_buffer), 0, 0, fname, ext); -#else - _splitpath(filepath.c_str(), drive, dir, fname, ext); - _makepath(path_buffer, drive, dir, 0, 0); - path = path_buffer; - _makepath(path_buffer, 0, 0, fname, ext); -#endif - file = path_buffer; - } - - //! Split full file name to path and filename - //! @param filepath [IN] Full file name inclusing path. - //! @param path [OUT] Extracted file path. - //! @param filename [OUT] Extracted file (without extension). - //! @param ext [OUT] Extracted files extension. - inline void Split(const QString& filepath, QString& path, QString& filename, QString& fext) - { - char path_buffer[_MAX_PATH]; - char drive[_MAX_DRIVE]; - char dir[_MAX_DIR]; - char fname[_MAX_FNAME]; - char ext[_MAX_EXT]; -#ifdef AZ_COMPILER_MSVC - _splitpath_s(filepath.toUtf8().data(), drive, AZ_ARRAY_SIZE(drive), dir, AZ_ARRAY_SIZE(dir), fname, AZ_ARRAY_SIZE(fname), ext, AZ_ARRAY_SIZE(ext)); - _makepath_s(path_buffer, AZ_ARRAY_SIZE(path_buffer), drive, dir, 0, 0); -#else - _splitpath(filepath.toUtf8().data(), drive, dir, fname, ext); - _makepath(path_buffer, drive, dir, 0, 0); -#endif - path = path_buffer; - filename = fname; - fext = ext; - } - inline void Split(const AZStd::string& filepath, AZStd::string& path, AZStd::string& filename, AZStd::string& fext) - { - char path_buffer[_MAX_PATH]; - char drive[_MAX_DRIVE]; - char dir[_MAX_DIR]; - char fname[_MAX_FNAME]; - char ext[_MAX_EXT]; -#ifdef AZ_COMPILER_MSVC - _splitpath_s(filepath.c_str(), drive, AZ_ARRAY_SIZE(drive), dir, AZ_ARRAY_SIZE(dir), fname, AZ_ARRAY_SIZE(fname), ext, AZ_ARRAY_SIZE(ext)); - _makepath_s(path_buffer, AZ_ARRAY_SIZE(path_buffer), drive, dir, 0, 0); -#else - _splitpath(filepath.c_str(), drive, dir, fname, ext); - _makepath(path_buffer, drive, dir, 0, 0); -#endif - path = path_buffer; - filename = fname; - fext = ext; - } - //! Split path into segments //! @param filepath [IN] path inline QStringList SplitIntoSegments(const QString& path) diff --git a/Code/Framework/AzCore/AzCore/IO/FileIO.h b/Code/Framework/AzCore/AzCore/IO/FileIO.h index 6406025417..25dd422a47 100644 --- a/Code/Framework/AzCore/AzCore/IO/FileIO.h +++ b/Code/Framework/AzCore/AzCore/IO/FileIO.h @@ -148,7 +148,7 @@ namespace AZ virtual AZ::u64 ModificationTime(HandleType fileHandle) = 0; virtual AZ::u64 ModificationTime(const char* filePath) = 0; - /// Get the size of the file. Returns Success if we report size. + /// Get the size of the file. Returns Success if we report size. virtual Result Size(const char* filePath, AZ::u64& size) = 0; virtual Result Size(HandleType fileHandle, AZ::u64& size) = 0; @@ -198,7 +198,7 @@ namespace AZ /// note: the callback will contain the full concatenated path (filePath + slash + fileName) /// not just the individual file name found. /// note: if the file path of the found file corresponds to a registered ALIAS, the longest matching alias will be returned - /// so expect return values like @assets@/textures/mytexture.dds instead of a full path. This is so that fileIO works over remote connections. + /// so expect return values like @products@/textures/mytexture.dds instead of a full path. This is so that fileIO works over remote connections. /// note: if rootPath is specified the implementation has the option of substituting it for the current directory /// as would be the case on a file server. typedef AZStd::function FindFilesCallbackType; @@ -206,13 +206,18 @@ namespace AZ // Alias system - /// SetAlias - Adds an alias to the path resolution system, e.g. @user@, @root@, etc. + /// SetAlias - Adds an alias to the path resolution system, e.g. @user@, @products@, etc. virtual void SetAlias(const char* alias, const char* path) = 0; /// ClearAlias - Removes an alias from the path resolution system virtual void ClearAlias(const char* alias) = 0; /// GetAlias - Returns the destination path for a given alias, or nullptr if the alias does not exist virtual const char* GetAlias(const char* alias) const = 0; + /// SetDeprecateAlias - Adds a deprecated alias with path resolution which points to a new alias + /// When the DeprecatedAlias is used an Error is logged and the alias is resolved to the path + /// specified by the new alais + virtual void SetDeprecatedAlias(AZStd::string_view oldAlias, AZStd::string_view newAlias) = 0; + /// Shorten the given path if it contains an alias. it will always pick the longest alias match. /// note that it re-uses the buffer, since the data can only get smaller and we don't want to internally allocate memory if we /// can avoid it. @@ -230,8 +235,8 @@ namespace AZ //! ResolvePath - Replaces any aliases in path with their values and stores the result in resolvedPath, //! also ensures that the path is absolute - //! NOTE: If the path does not start with an alias then the resolved value of the @assets@ is used - //! which has the effect of making the path relative to the @assets@/ folder + //! NOTE: If the path does not start with an alias then the resolved value of the @products@ is used + //! which has the effect of making the path relative to the @products@/ folder //! returns true if path was resolved, false otherwise //! note that all of the above file-finding and opening functions automatically resolve the path before operating //! so you should not need to call this except in very exceptional circumstances where you absolutely need to diff --git a/Code/Framework/AzCore/AzCore/IO/IStreamer.h b/Code/Framework/AzCore/AzCore/IO/IStreamer.h index d959fa716c..438384e687 100644 --- a/Code/Framework/AzCore/AzCore/IO/IStreamer.h +++ b/Code/Framework/AzCore/AzCore/IO/IStreamer.h @@ -42,8 +42,8 @@ namespace AZ::IO // These functions can't be called after a request has been queued. // - //! Creates a request to read a file. - //! @param relativePath Relative path to the file to load. This can include aliases such as @assets@. + //! Creates a request to read a file. + //! @param relativePath Relative path to the file to load. This can include aliases such as @products@. //! @param outputBuffer The buffer that will hold the loaded data. This must be able to at least hold "size" number of bytes. //! @param outputBufferSize The size of the buffer that will hold the loaded data. This must be equal or larger than "size" number of bytes. //! @param readSize The number of bytes to read from the file at the relative path. @@ -62,9 +62,9 @@ namespace AZ::IO IStreamerTypes::Priority priority = IStreamerTypes::s_priorityMedium, size_t offset = 0) = 0; - //! Sets a request to the read command. + //! Sets a request to the read command. //! @param request The request that will store the read command. - //! @param relativePath Relative path to the file to load. This can include aliases such as @assets@. + //! @param relativePath Relative path to the file to load. This can include aliases such as @products@. //! @param outputBuffer The buffer that will hold the loaded data. This must be able to at least hold "size" number of bytes. //! @param outputBufferSize The size of the buffer that will hold the loaded data. This must be equal or larger than "size" number of bytes. //! @param readSize The number of bytes to read from the file at the relative path. @@ -84,8 +84,8 @@ namespace AZ::IO IStreamerTypes::Priority priority = IStreamerTypes::s_priorityMedium, size_t offset = 0) = 0; - //! Creates a request to the read command. - //! @param relativePath Relative path to the file to load. This can include aliases such as @assets@. + //! Creates a request to the read command. + //! @param relativePath Relative path to the file to load. This can include aliases such as @products@. //! @param allocator The allocator used to reserve and release memory for the read request. Memory allocated this way will //! be automatically freed when there are no more references to the FileRequestPtr. To avoid this, use GetReadRequestResult //! to claim the pointer and use the provided allocator to release the memory at a later point. @@ -106,9 +106,9 @@ namespace AZ::IO IStreamerTypes::Priority priority = IStreamerTypes::s_priorityMedium, size_t offset = 0) = 0; - //! Sets a request to the read command. + //! Sets a request to the read command. //! @param request The request that will store the read command. - //! @param relativePath Relative path to the file to load. This can include aliases such as @assets@. + //! @param relativePath Relative path to the file to load. This can include aliases such as @products@. //! @param allocator The allocator used to reserve and release memory for the read request. Memory allocated this way will //! be automatically freed when there are no more references to the FileRequestPtr. To avoid this, use GetReadRequestResult //! to claim the pointer and use the provided allocator to release the memory at a later point. @@ -138,7 +138,7 @@ namespace AZ::IO //! @result A smart pointer to the newly created request with the cancel command. virtual FileRequestPtr Cancel(FileRequestPtr target) = 0; - //! Sets a request to the cancel command. + //! Sets a request to the cancel command. //! When this request completes it's not guaranteed to have canceled the target request. Not all requests can be canceled and requests //! that already processing may complete. It's recommended to let the target request handle the completion of the request as normal //! and handle cancellation by checking the status on the target request is set to IStreamerTypes::RequestStatus::Canceled. @@ -177,7 +177,7 @@ namespace AZ::IO //! DestroyDedicatedCache is called. Typical use of a dedicated cache is for files that have their own compression //! and are periodically visited to read a section, e.g. streaming video play or streaming audio banks. This //! request will fail if there are no nodes in Streamer's stack that deal with dedicated caches. - //! @param relativePath Relative path to the file to receive a dedicated cache. This can include aliases such as @assets@. + //! @param relativePath Relative path to the file to receive a dedicated cache. This can include aliases such as @products@. //! @return A smart pointer to the newly created request with the command to create a dedicated cache. virtual FileRequestPtr CreateDedicatedCache(AZStd::string_view relativePath) = 0; @@ -186,25 +186,25 @@ namespace AZ::IO //! and are periodically visited to read a section, e.g. streaming video play or streaming audio banks. This //! request will fail if there are no nodes in Streamer's stack that deal with dedicated caches. //! @param request The request that will store the command to create a dedicated cache. - //! @param relativePath Relative path to the file to receive a dedicated cache. This can include aliases such as @assets@. + //! @param relativePath Relative path to the file to receive a dedicated cache. This can include aliases such as @products@. //! @return A reference to the provided request. virtual FileRequestPtr& CreateDedicatedCache(FileRequestPtr& request, AZStd::string_view relativePath) = 0; //! Destroy a dedicated cache created by CreateDedicatedCache. See CreateDedicatedCache for more details. - //! @param relativePath Relative path to the file that got a dedicated cache. This can include aliases such as @assets@. + //! @param relativePath Relative path to the file that got a dedicated cache. This can include aliases such as @products@. //! @return A smart pointer to the newly created request with the command to destroy a dedicated cache. virtual FileRequestPtr DestroyDedicatedCache(AZStd::string_view relativePath) = 0; //! Destroy a dedicated cache created by CreateDedicatedCache. See CreateDedicatedCache for more details. //! @param request The request that will store the command to destroy a dedicated cache. - //! @param relativePath Relative path to the file that got a dedicated cache. This can include aliases such as @assets@. + //! @param relativePath Relative path to the file that got a dedicated cache. This can include aliases such as @products@. //! @return A reference to the provided request. virtual FileRequestPtr& DestroyDedicatedCache(FileRequestPtr& request, AZStd::string_view relativePath) = 0; //! Clears a file from all caches in use by Streamer. //! Flushing the cache will cause the streaming stack to pause processing until it's idle before issuing the flush and resuming //! processing. This can result in a noticeable interruption. - //! @param relativePath Relative path to the file that will be cleared from all caches. This can include aliases such as @assets@. + //! @param relativePath Relative path to the file that will be cleared from all caches. This can include aliases such as @products@. //! @return A smart pointer to the newly created request with the command to flush a file from all caches. virtual FileRequestPtr FlushCache(AZStd::string_view relativePath) = 0; @@ -212,7 +212,7 @@ namespace AZ::IO //! Flushing the cache will cause the streaming stack to pause processing until it's idle before issuing the flush and resuming //! processing. This can result in a noticeable interruption. //! @param request The request that will store the command to flush a file from all caches. - //! @param relativePath Relative path to the file that will be cleared from all caches. This can include aliases such as @assets@. + //! @param relativePath Relative path to the file that will be cleared from all caches. This can include aliases such as @products@. //! @return A reference to the provided request. virtual FileRequestPtr& FlushCache(FileRequestPtr& request, AZStd::string_view relativePath) = 0; @@ -334,7 +334,7 @@ namespace AZ::IO // //! Collect statistics from all the components that make up Streamer. - //! This is thread safe in the sense that it won't crash. + //! This is thread safe in the sense that it won't crash. //! Data is collected lockless from involved threads and might be slightly //! out of date in some cases. //! @param statistics The container where statistics will be added to. diff --git a/Code/Framework/AzCore/AzCore/IO/Path/Path.h b/Code/Framework/AzCore/AzCore/IO/Path/Path.h index 24f26daa51..3b5c224957 100644 --- a/Code/Framework/AzCore/AzCore/IO/Path/Path.h +++ b/Code/Framework/AzCore/AzCore/IO/Path/Path.h @@ -98,6 +98,11 @@ namespace AZ::IO //! made from the internal string constexpr AZStd::fixed_string FixedMaxPathString() const noexcept; + // as_posix + //! Replicates the behavior of the Python pathlib as_posix method + //! by replacing the Windows Path Separator with the Posix Path Seperator + constexpr AZStd::fixed_string FixedMaxPathStringAsPosix() const noexcept; + // decomposition //! Given a windows path of "C:\O3DE\foo\bar\name.txt" and a posix path of //! "/O3DE/foo/bar/name.txt" @@ -178,7 +183,7 @@ namespace AZ::IO //! Normalizes a path in a purely lexical manner. //! # Path separators are converted to their preferred path separator //! # Path parts of "." are collapsed to nothing empty - //! # Paths parts of ".." are removed if there is a preceding directory + //! # Paths parts of ".." are removed if there is a preceding directory //! The preceding directory is also removed //! # Runs of Two or more path separators are collapsed into one path separator //! unless the path begins with two path separators @@ -238,7 +243,7 @@ namespace AZ::IO // iterators //! Returns an iterator to the beginning of the path that can be used to traverse the path - //! according to the following + //! according to the following //! 1. Root name - (0 or 1) //! 2. Root directory - (0 or 1) //! 3. Filename - (0 or more) @@ -253,24 +258,23 @@ namespace AZ::IO template friend class BasicPath; friend struct AZStd::hash; - - template - static constexpr void MakeRelativeTo(PathResultType& pathResult, const AZ::IO::PathView& path, const AZ::IO::PathView& base); - struct PathIterable; + + static constexpr void MakeRelativeTo(PathIterable& pathResult, const AZ::IO::PathView& path, const AZ::IO::PathView& base) noexcept; + //! Returns a structure that provides a view of the path parts which can be used for iteration //! Only the path parts that correspond to creating an normalized path is returned //! This function is useful for returning a "view" into a normalized path without the need //! to allocate memory for the heap static constexpr PathIterable GetNormalPathParts(const AZ::IO::PathView& path) noexcept; - // joins the input path to the Path Iterable structure using similiar logic to Path::Append - // If the input path is absolute it will replace the current PathIterable otherwise - // the input path will be appended to the Path Iterable structure - // For example a PathIterable with parts = ['C:', '/', 'foo'] - // If the path input = 'bar', then the new PathIterable parts = [C:', '/', 'foo', 'bar'] - // If the path input = 'C:/bar', then the new PathIterable parts = [C:', '/', 'bar'] - // If the path input = 'C:bar', then the new PathIterable parts = [C:', '/', 'foo', 'bar' ] - // If the path input = 'D:bar', then the new PathIterable parts = [D:, 'bar' ] + //! joins the input path to the Path Iterable structure using similiar logic to Path::Append + //! If the input path is absolute it will replace the current PathIterable otherwise + //! the input path will be appended to the Path Iterable structure + //! For example a PathIterable with parts = ['C:', '/', 'foo'] + //! If the path input = 'bar', then the new PathIterable parts = [C:', '/', 'foo', 'bar'] + //! If the path input = 'C:/bar', then the new PathIterable parts = [C:', '/', 'bar'] + //! If the path input = 'C:bar', then the new PathIterable parts = [C:', '/', 'foo', 'bar' ] + //! If the path input = 'D:bar', then the new PathIterable parts = [D:, 'bar' ] static constexpr void AppendNormalPathParts(PathIterable& pathIterableResult, const AZ::IO::PathView& path) noexcept; constexpr int ComparePathView(const PathView& other) const; @@ -325,32 +329,32 @@ namespace AZ::IO constexpr BasicPath(BasicPath&& other) = default; // Conversion constructor for other types of BasicPath instantiations - constexpr BasicPath(const PathView& other); + constexpr BasicPath(const PathView& other) noexcept; // String constructors //! Constructs a Path by copying the pathString to its internal string //! The preferred separator is to the OS default path separator constexpr BasicPath(const string_type& pathString) noexcept; //! Constructs a Path by copying the pathString to its internal string - //! The preferred separator it set to the parameter + //! The preferred separator is set to the parameter constexpr BasicPath(const string_type& pathString, const char preferredSeparator) noexcept; //! Constructs a Path by moving the pathString to its internal string //! The preferred separator is to the OS default path separator constexpr BasicPath(string_type&& pathString) noexcept; //! Constructs a Path by copying the pathString to its internal string - //! The preferred separator it set to the parameter + //! The preferred separator is set to the parameter constexpr BasicPath(string_type&& pathString, const char preferredSeparator) noexcept; //! Constructs a Path by constructing it's internal out of a string_view //! The preferred separator is to the OS default path separator constexpr BasicPath(AZStd::string_view src) noexcept; //! Constructs a Path by constructing it's internal out of a string_view - //! The preferred separators it set to the parameter + //! The preferred separator is set to the parameter constexpr BasicPath(AZStd::string_view src, const char preferredSeparator) noexcept; //! Constructs a Path by constructing it's internal out of a value_type* //! The preferred separator is to the OS default path separator constexpr BasicPath(const value_type* pathString) noexcept; //! Constructs a Path by constructing it's internal out of a value_type* - //! The preferred separator it set to the parameter + //! The preferred separator is set to the parameter constexpr BasicPath(const value_type* pathString, const char preferredSeparator) noexcept; //! Constructs a empty Path with the preferred separator set to the parameter explicit constexpr BasicPath(const char preferredSeparator) noexcept; @@ -371,7 +375,7 @@ namespace AZ::IO constexpr BasicPath& operator=(BasicPath&& other) = default; // conversion assignment operator - constexpr BasicPath& operator=(const PathView& pathView); + constexpr BasicPath& operator=(const PathView& pathView) noexcept; constexpr BasicPath& operator=(const string_type& str) noexcept; constexpr BasicPath& operator=(string_type&& str) noexcept; constexpr BasicPath& operator=(AZStd::string_view str) noexcept; @@ -477,6 +481,12 @@ namespace AZ::IO //! made from the internal string constexpr AZStd::fixed_string FixedMaxPathString() const; + // as_posix + //! Replicates the behavior of the Python pathlib as_posix method + //! by replacing the Windows Path Separator with the Posix Path Seperator + AZStd::string StringAsPosix() const; + constexpr AZStd::fixed_string FixedMaxPathStringAsPosix() const noexcept; + // compare //! Performs a compare of each of the path parts for equivalence //! Each part of the path is compare using string comparison @@ -574,7 +584,7 @@ namespace AZ::IO //! Normalizes a path in a purely lexical manner. //! # Path separators are converted to their preferred path separator //! # Path parts of "." are collapsed to nothing empty - //! # Paths parts of ".." are removed if there is a preceding directory + //! # Paths parts of ".." are removed if there is a preceding directory //! The preceding directory is also removed //! # Runs of Two or more path separators are collapsed into one path separator //! unless the path begins with two path separators @@ -616,7 +626,7 @@ namespace AZ::IO // iterators //! Returns an iterator to the beginning of the path that can be used to traverse the path - //! according to the following + //! according to the following //! 1. Root name - (0 or 1) //! 2. Root directory - (0 or 1) //! 3. Filename - (0 or more) diff --git a/Code/Framework/AzCore/AzCore/IO/Path/Path.inl b/Code/Framework/AzCore/AzCore/IO/Path/Path.inl index 0147ad3356..1d654c1502 100644 --- a/Code/Framework/AzCore/AzCore/IO/Path/Path.inl +++ b/Code/Framework/AzCore/AzCore/IO/Path/Path.inl @@ -240,6 +240,14 @@ namespace AZ::IO return AZStd::fixed_string(m_path.begin(), m_path.end()); } + // as_posix + constexpr AZStd::fixed_string PathView::FixedMaxPathStringAsPosix() const noexcept + { + AZStd::fixed_string resultPath(m_path.begin(), m_path.end()); + AZStd::replace(resultPath.begin(), resultPath.end(), AZ::IO::WindowsPathSeparator, AZ::IO::PosixPathSeparator); + return resultPath; + } + // decomposition constexpr auto PathView::RootName() const -> PathView { @@ -473,8 +481,7 @@ namespace AZ::IO return lhs.Compare(rhs) >= 0; } - template - constexpr void PathView::MakeRelativeTo(PathResultType& pathResult, const AZ::IO::PathView& path, const AZ::IO::PathView& base) + constexpr void PathView::MakeRelativeTo(PathIterable& pathIterable, const AZ::IO::PathView& path, const AZ::IO::PathView& base) noexcept { const bool exactCaseCompare = path.m_preferred_separator == PosixPathSeparator || base.m_preferred_separator == PosixPathSeparator; @@ -492,13 +499,11 @@ namespace AZ::IO if (int res = Internal::ComparePathSegment(*pathParser, *pathParserBase, exactCaseCompare); res != 0) { - pathResult.m_path = AZStd::string_view{}; return; } } else if (CheckIterMismatchAtBase()) { - pathResult.m_path = AZStd::string_view{}; return; } @@ -512,7 +517,6 @@ namespace AZ::IO } if (CheckIterMismatchAtBase()) { - pathResult.m_path = AZStd::string_view{}; return; } } @@ -530,7 +534,7 @@ namespace AZ::IO // If there is no mismatch, return ".". if (!pathParser && !pathParserBase) { - pathResult.m_path = AZStd::string_view{ "." }; + pathIterable.emplace_back(".", parser::PathPartKind::PK_Dot); return; } @@ -539,27 +543,25 @@ namespace AZ::IO int elemCount = parser::DetermineLexicalElementCount(pathParserBase); if (elemCount < 0) { - pathResult.m_path = AZStd::string_view{}; return; } // if elemCount == 0 and (pathParser == end() || pathParser->empty()), returns path("."); otherwise if (elemCount == 0 && (pathParser.AtEnd() || *pathParser == "")) { - pathResult.m_path = AZStd::string_view{ "." }; + pathIterable.emplace_back(".", parser::PathPartKind::PK_Dot); return; } // return a path constructed with 'n' dot-dot elements, followed by the // elements of '*this' after the mismatch. - pathResult = PathResultType(path.m_preferred_separator); while (elemCount--) { - pathResult /= ".."; + pathIterable.emplace_back("..", parser::PathPartKind::PK_DotDot); } for (; pathParser; ++pathParser) { - pathResult /= *pathParser; + pathIterable.emplace_back(*pathParser, parser::ClassifyPathPart(pathParser)); } } @@ -673,7 +675,7 @@ namespace AZ::IO // Basic Path implementation template - constexpr BasicPath::BasicPath(const PathView& other) + constexpr BasicPath::BasicPath(const PathView& other) noexcept : m_path(other.m_path) , m_preferred_separator(other.m_preferred_separator) {} @@ -726,6 +728,7 @@ namespace AZ::IO : m_path(first, last) , m_preferred_separator(preferredSeparator) {} + template constexpr BasicPath::operator PathView() const noexcept { @@ -733,7 +736,7 @@ namespace AZ::IO } template - constexpr auto BasicPath::operator=(const PathView& other) -> BasicPath& + constexpr auto BasicPath::operator=(const PathView& other) noexcept -> BasicPath& { m_path = other.m_path; m_preferred_separator = other.m_preferred_separator; @@ -974,13 +977,13 @@ namespace AZ::IO template constexpr auto BasicPath::MakePreferred() -> BasicPath& { - if (m_preferred_separator != '/') + if (m_preferred_separator != PosixPathSeparator) { - AZStd::replace(m_path.begin(), m_path.end(), '/', m_preferred_separator); + AZStd::replace(m_path.begin(), m_path.end(), PosixPathSeparator, m_preferred_separator); } else { - AZStd::replace(m_path.begin(), m_path.end(), '\\', m_preferred_separator); + AZStd::replace(m_path.begin(), m_path.end(), WindowsPathSeparator, m_preferred_separator); } return *this; } @@ -1033,6 +1036,24 @@ namespace AZ::IO return AZStd::fixed_string(m_path.begin(), m_path.end()); } + // as_posix + // Returns a copy of the path with the path separators converted to PosixPathSeparator + template + AZStd::string BasicPath::StringAsPosix() const + { + AZStd::string resultPath(m_path.begin(), m_path.end()); + AZStd::replace(resultPath.begin(), resultPath.end(), WindowsPathSeparator, PosixPathSeparator); + return resultPath; + } + + template + constexpr AZStd::fixed_string BasicPath::FixedMaxPathStringAsPosix() const noexcept + { + AZStd::fixed_string resultPath(m_path.begin(), m_path.end()); + AZStd::replace(resultPath.begin(), resultPath.end(), WindowsPathSeparator, PosixPathSeparator); + return resultPath; + } + template constexpr void BasicPath::swap(BasicPath& rhs) noexcept { @@ -1234,6 +1255,7 @@ namespace AZ::IO { pathResult /= pathPartView; } + return pathResult; } @@ -1241,7 +1263,13 @@ namespace AZ::IO constexpr auto BasicPath::LexicallyRelative(const PathView& base) const -> BasicPath { BasicPath pathResult(m_preferred_separator); - static_cast(*this).MakeRelativeTo(pathResult, *this, base); + PathView::PathIterable pathIterable; + PathView::MakeRelativeTo(pathIterable, *this, base); + for ([[maybe_unused]] auto [pathPartView, pathPartKind] : pathIterable) + { + pathResult /= pathPartView; + } + return pathResult; } @@ -1355,7 +1383,7 @@ namespace AZ::IO return !basePathParts.empty() || !thisPathParts.IsAbsolute(); } - constexpr FixedMaxPath PathView::LexicallyNormal() const + constexpr auto PathView::LexicallyNormal() const -> FixedMaxPath { FixedMaxPath pathResult(m_preferred_separator); PathIterable pathIterable = GetNormalPathParts(*this); @@ -1367,21 +1395,28 @@ namespace AZ::IO return pathResult; } - constexpr FixedMaxPath PathView::LexicallyRelative(const PathView& base) const + constexpr auto PathView::LexicallyRelative(const PathView& base) const -> FixedMaxPath { FixedMaxPath pathResult(m_preferred_separator); - MakeRelativeTo(pathResult, *this, base); + PathIterable pathIterable; + MakeRelativeTo(pathIterable, *this, base); + for ([[maybe_unused]] auto [pathPartView, pathPartKind] : pathIterable) + { + pathResult /= pathPartView; + } + return pathResult; } - constexpr FixedMaxPath PathView::LexicallyProximate(const PathView& base) const + constexpr auto PathView::LexicallyProximate(const PathView& base) const -> FixedMaxPath { - FixedMaxPath result = LexicallyRelative(base); - if (result.empty()) + FixedMaxPath pathResult = LexicallyRelative(base); + if (pathResult.empty()) { return FixedMaxPath(*this); } - return result; + + return pathResult; } } diff --git a/Code/Framework/AzCore/AzCore/IO/Path/PathIterable.inl b/Code/Framework/AzCore/AzCore/IO/Path/PathIterable.inl index a1faa29b31..e700ab0196 100644 --- a/Code/Framework/AzCore/AzCore/IO/Path/PathIterable.inl +++ b/Code/Framework/AzCore/AzCore/IO/Path/PathIterable.inl @@ -49,8 +49,8 @@ namespace AZ::IO constexpr void clear() noexcept; - friend constexpr auto PathView::GetNormalPathParts(const AZ::IO::PathView&) noexcept -> PathIterable; friend constexpr auto PathView::AppendNormalPathParts(PathIterable& pathIterable, const AZ::IO::PathView&) noexcept -> void; + friend constexpr auto PathView::MakeRelativeTo(PathIterable& pathIterable, const AZ::IO::PathView&, const AZ::IO::PathView&) noexcept -> void; PartKindArray m_parts{}; size_t m_size{}; }; diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp index e1bd717e7b..36f66312d8 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp @@ -546,7 +546,7 @@ namespace AZ::SettingsRegistryMergeUtils AZ::IO::FixedMaxPath path = AZ::Utils::GetExecutableDirectory(); registry.Set(FilePathKey_BinaryFolder, path.LexicallyNormal().Native()); - // Engine root folder - corresponds to the @engroot@ and @devroot@ aliases + // Engine root folder - corresponds to the @engroot@ and @engroot@ aliases AZ::IO::FixedMaxPath engineRoot = FindEngineRoot(registry); registry.Set(FilePathKey_EngineRootFolder, engineRoot.LexicallyNormal().Native()); @@ -570,7 +570,7 @@ namespace AZ::SettingsRegistryMergeUtils assetPlatform = AZ::OSPlatformToDefaultAssetPlatform(AZ_TRAIT_OS_PLATFORM_CODENAME); } - // Project path - corresponds to the @devassets@ alias + // Project path - corresponds to the @projectroot@ alias // NOTE: Here we append to engineRoot, but if projectPathValue is absolute then engineRoot is discarded. path = engineRoot / projectPathValue; @@ -662,7 +662,7 @@ namespace AZ::SettingsRegistryMergeUtils } else { - // Cache: root - same as the @root@ alias, this is the starting path for cache files. + // Cache: root - same as the @products@ alias, this is the starting path for cache files. path = normalizedProjectPath / "Cache"; registry.Set(FilePathKey_CacheProjectRootFolder, path.LexicallyNormal().Native()); path /= assetPlatform; diff --git a/Code/Framework/AzCore/AzCore/UnitTest/Mocks/MockFileIOBase.h b/Code/Framework/AzCore/AzCore/UnitTest/Mocks/MockFileIOBase.h index c9b7d44e1f..d7d0789c1a 100644 --- a/Code/Framework/AzCore/AzCore/UnitTest/Mocks/MockFileIOBase.h +++ b/Code/Framework/AzCore/AzCore/UnitTest/Mocks/MockFileIOBase.h @@ -52,6 +52,7 @@ namespace AZ MOCK_METHOD2(SetAlias, void(const char* alias, const char* path)); MOCK_METHOD1(ClearAlias, void(const char* alias)); MOCK_CONST_METHOD1(GetAlias, const char*(const char* alias)); + MOCK_METHOD2(SetDeprecatedAlias, void(AZStd::string_view, AZStd::string_view)); MOCK_CONST_METHOD2(ConvertToAlias, AZStd::optional(char* inOutBuffer, AZ::u64 bufferLength)); MOCK_CONST_METHOD2(ConvertToAlias, bool(AZ::IO::FixedMaxPath& aliasPath, const AZ::IO::PathView& path)); MOCK_CONST_METHOD3(ResolvePath, bool(const char* path, char* resolvedPath, AZ::u64 resolvedPathSize)); diff --git a/Code/Framework/AzCore/AzCore/Utils/Utils.cpp b/Code/Framework/AzCore/AzCore/Utils/Utils.cpp index c4dd24be35..2031d14d08 100644 --- a/Code/Framework/AzCore/AzCore/Utils/Utils.cpp +++ b/Code/Framework/AzCore/AzCore/Utils/Utils.cpp @@ -51,6 +51,20 @@ namespace AZ::Utils return executableDirectory; } + AZStd::optional ConvertToAbsolutePath(AZStd::string_view path) + { + AZ::IO::FixedMaxPathString absolutePath; + AZ::IO::FixedMaxPathString srcPath{ path }; + if (ConvertToAbsolutePath(srcPath.c_str(), absolutePath.data(), absolutePath.capacity())) + { + // Fix the size value of the fixed string by calculating the c-string length using char traits + absolutePath.resize_no_construct(AZStd::char_traits::length(absolutePath.data())); + return srcPath; + } + + return AZStd::nullopt; + } + AZ::IO::FixedMaxPathString GetEngineManifestPath() { AZ::IO::FixedMaxPath o3deManifestPath = GetO3deManifestDirectory(); diff --git a/Code/Framework/AzCore/AzCore/Utils/Utils.h b/Code/Framework/AzCore/AzCore/Utils/Utils.h index d8d4290f7f..c147e38bfb 100644 --- a/Code/Framework/AzCore/AzCore/Utils/Utils.h +++ b/Code/Framework/AzCore/AzCore/Utils/Utils.h @@ -104,6 +104,7 @@ namespace AZ // Attempts the supplied path to an absolute path. //! Returns nullopt if path cannot be converted to an absolute path AZStd::optional ConvertToAbsolutePath(AZStd::string_view path); + bool ConvertToAbsolutePath(const char* path, char* absolutePath, AZ::u64 absolutePathMaxSize); //! Save a string to a file. Otherwise returns a failure with error message. AZ::Outcome WriteFile(AZStd::string_view content, AZStd::string_view filePath); diff --git a/Code/Framework/AzCore/Platform/Android/AzCore/Utils/Utils_Android.cpp b/Code/Framework/AzCore/Platform/Android/AzCore/Utils/Utils_Android.cpp index 1333006c4c..9a3f825bfc 100644 --- a/Code/Framework/AzCore/Platform/Android/AzCore/Utils/Utils_Android.cpp +++ b/Code/Framework/AzCore/Platform/Android/AzCore/Utils/Utils_Android.cpp @@ -60,23 +60,34 @@ namespace AZ return writeStorage ? AZStd::make_optional(writeStorage) : AZStd::nullopt; } - AZStd::optional ConvertToAbsolutePath(AZStd::string_view path) + bool ConvertToAbsolutePath(const char* path, char* absolutePath, AZ::u64 maxLength) { - AZ::IO::FixedMaxPathString absolutePath; - AZ::IO::FixedMaxPathString srcPath{ path }; - if (AZ::Android::Utils::IsApkPath(srcPath.c_str())) + if (AZ::Android::Utils::IsApkPath(path)) { - return srcPath; + azstrcpy(absolutePath, maxLength, path); + return true; } - if(char* result = realpath(srcPath.c_str(), absolutePath.data()); result) +#ifdef PATH_MAX + static constexpr size_t UnixMaxPathLength = PATH_MAX; +#else + // Fallback to 4096 if the PATH_MAX macro isn't defined on the Unix System + static constexpr size_t UnixMaxPathLength = 4096; +#endif + if (!AZ::IO::PathView(path).IsAbsolute()) { - // Fix the size value of the fixed string by calculating the c-string length using char traits - absolutePath.resize_no_construct(AZStd::char_traits::length(absolutePath.data())); - return absolutePath; + // note that realpath fails if the path does not exist and actually changes the return value + // to be the actual place that FAILED, which we don't want. + // if we fail, we'd prefer to fall through and at least use the original path. + char absolutePathBuffer[UnixMaxPathLength]; + if (const char* result = realpath(path, absolutePathBuffer); result != nullptr) + { + azstrcpy(absolutePath, maxLength, absolutePathBuffer); + return true; + } } - - return AZStd::nullopt; + azstrcpy(absolutePath, maxLength, path); + return AZ::IO::PathView(absolutePath).IsAbsolute(); } } } diff --git a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Utils/Utils_UnixLike.cpp b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Utils/Utils_UnixLike.cpp index 2e31936057..7327c8f152 100644 --- a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Utils/Utils_UnixLike.cpp +++ b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Utils/Utils_UnixLike.cpp @@ -47,23 +47,32 @@ namespace AZ AZ::IO::FixedMaxPath path{pass->pw_dir}; return path.Native(); } - + return {}; } - AZStd::optional ConvertToAbsolutePath(AZStd::string_view path) + bool ConvertToAbsolutePath(const char* path, char* absolutePath, AZ::u64 maxLength) { - AZ::IO::FixedMaxPathString absolutePath; - AZ::IO::FixedMaxPathString srcPath{ path }; - - if (char* result = realpath(srcPath.c_str(), absolutePath.data()); result) +#ifdef PATH_MAX + static constexpr size_t UnixMaxPathLength = PATH_MAX; +#else + // Fallback to 4096 if the PATH_MAX macro isn't defined on the Unix System + static constexpr size_t UnixMaxPathLength = 4096; +#endif + if (!AZ::IO::PathView(path).IsAbsolute()) { - // Fix the size value of the fixed string by calculating the c-string length using char traits - absolutePath.resize_no_construct(AZStd::char_traits::length(absolutePath.data())); - return absolutePath; + // note that realpath fails if the path does not exist and actually changes the return value + // to be the actual place that FAILED, which we don't want. + // if we fail, we'd prefer to fall through and at least use the original path. + char absolutePathBuffer[UnixMaxPathLength]; + if (const char* result = realpath(path, absolutePathBuffer); result != nullptr) + { + azstrcpy(absolutePath, maxLength, absolutePathBuffer); + return true; + } } - - return AZStd::nullopt; + azstrcpy(absolutePath, maxLength, path); + return AZ::IO::PathView(absolutePath).IsAbsolute(); } } // namespace Utils } // namespace AZ diff --git a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Utils/Utils_WinAPI.cpp b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Utils/Utils_WinAPI.cpp index bcba24b768..24786e2bc9 100644 --- a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Utils/Utils_WinAPI.cpp +++ b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Utils/Utils_WinAPI.cpp @@ -67,19 +67,12 @@ namespace AZ return AZStd::nullopt; } - AZStd::optional ConvertToAbsolutePath(AZStd::string_view path) + bool ConvertToAbsolutePath(const char* path, char* absolutePath, AZ::u64 maxLength) { - AZ::IO::FixedMaxPathString absolutePath; - AZ::IO::FixedMaxPathString srcPath{ path }; - char* result = _fullpath(absolutePath.data(), srcPath.c_str(), absolutePath.capacity()); - // Force update of the fixed_string size() value - absolutePath.resize_no_construct(AZStd::char_traits::length(absolutePath.data())); - if (result) - { - return absolutePath; - } - - return AZStd::nullopt; + char* result = _fullpath(absolutePath, path, maxLength); + return result != nullptr; } + + } } diff --git a/Code/Framework/AzCore/Tests/FileIOBaseTestTypes.h b/Code/Framework/AzCore/Tests/FileIOBaseTestTypes.h index 26b3df55bb..5897b3aaee 100644 --- a/Code/Framework/AzCore/Tests/FileIOBaseTestTypes.h +++ b/Code/Framework/AzCore/Tests/FileIOBaseTestTypes.h @@ -426,6 +426,10 @@ public: return nullptr; } + void SetDeprecatedAlias(AZStd::string_view, AZStd::string_view) override + { + } + void ClearAlias(const char* ) override { } AZStd::optional ConvertToAlias(char* inOutBuffer, AZ::u64) const override diff --git a/Code/Framework/AzCore/Tests/IO/Path/PathTests.cpp b/Code/Framework/AzCore/Tests/IO/Path/PathTests.cpp index 34076a10f6..cf239a0821 100644 --- a/Code/Framework/AzCore/Tests/IO/Path/PathTests.cpp +++ b/Code/Framework/AzCore/Tests/IO/Path/PathTests.cpp @@ -698,7 +698,7 @@ AZ_POP_DISABLE_WARNING using PathViewLexicallyProximateFixture = PathLexicallyFixture; - TEST_P(PathViewLexicallyProximateFixture, LexicallyProximate_ReturnsRelativePathIfNotEmptyOrTestPathIfNot) + TEST_P(PathViewLexicallyProximateFixture, LexicallyProximate_ReturnsRelativePathIfNotEmptyOrTestPath) { const auto& testParams = GetParam(); AZ::IO::PathView testPath(testParams.m_testPathString, testParams.m_preferredSeparator); diff --git a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp index e72e2de472..1f99a594fa 100644 --- a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp +++ b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp @@ -77,11 +77,15 @@ namespace AzFramework { + namespace ApplicationInternal { static constexpr const char s_prefabSystemKey[] = "/Amazon/Preferences/EnablePrefabSystem"; static constexpr const char s_prefabWipSystemKey[] = "/Amazon/Preferences/EnablePrefabSystemWipFeatures"; static constexpr const char s_legacySlicesAssertKey[] = "/Amazon/Preferences/ShouldAssertForLegacySlicesUsage"; + static constexpr const char* DeprecatedFileIOAliasesRoot = "/O3DE/AzCore/FileIO/DeprecatedAliases"; + static constexpr const char* DeprecatedFileIOAliasesOldAliasKey = "OldAlias"; + static constexpr const char* DeprecatedFileIOAliasesNewAliasKey = "NewAlias"; } Application::Application() @@ -563,6 +567,68 @@ namespace AzFramework } } + struct DeprecatedAliasesKeyVisitor + : AZ::SettingsRegistryInterface::Visitor + { + using VisitResponse = AZ::SettingsRegistryInterface::VisitResponse; + using VisitAction = AZ::SettingsRegistryInterface::VisitAction; + using Type = AZ::SettingsRegistryInterface::Type; + + using AZ::SettingsRegistryInterface::Visitor::Visit; + + VisitResponse Traverse(AZStd::string_view path, AZStd::string_view, + VisitAction action, Type type) override + { + if (action == AZ::SettingsRegistryInterface::VisitAction::Begin) + { + if (type == AZ::SettingsRegistryInterface::Type::Array) + { + m_parentArrayPath = path; + } + + // Strip off last path segment from json path and check if is a child element of the array + if (AZ::StringFunc::TokenizeLast(path, '/'); + m_parentArrayPath == path) + { + m_aliases.emplace_back(); + } + } + else if (action == AZ::SettingsRegistryInterface::VisitAction::End) + { + if (type == AZ::SettingsRegistryInterface::Type::Array) + { + m_parentArrayPath = AZStd::string{}; + } + } + + return AZ::SettingsRegistryInterface::VisitResponse::Continue; + } + + void Visit(AZStd::string_view, AZStd::string_view valueName, Type, AZStd::string_view value) override + { + if (!m_aliases.empty()) + { + if (valueName == ApplicationInternal::DeprecatedFileIOAliasesOldAliasKey) + { + m_aliases.back().m_oldAlias = value; + } + else if (valueName == ApplicationInternal::DeprecatedFileIOAliasesNewAliasKey) + { + m_aliases.back().m_newAlias = value; + } + } + } + + struct AliasPair + { + AZStd::string m_oldAlias; + AZStd::string m_newAlias; + }; + AZStd::vector m_aliases; + + private: + AZStd::string m_parentArrayPath; + }; static void CreateUserCache(const AZ::IO::FixedMaxPath& cacheUserPath, AZ::IO::FileIOBase& fileIoBase) { @@ -610,9 +676,8 @@ namespace AzFramework void Application::SetFileIOAliases() { - if (m_archiveFileIO) + if (auto fileIoBase = m_archiveFileIO.get(); fileIoBase) { - auto fileIoBase = m_archiveFileIO.get(); // Set up the default file aliases based on the settings registry fileIoBase->SetAlias("@engroot@", GetEngineRoot()); fileIoBase->SetAlias("@projectroot@", GetEngineRoot()); @@ -620,29 +685,20 @@ namespace AzFramework { AZ::IO::FixedMaxPath pathAliases; - if (m_settingsRegistry->Get(pathAliases.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheProjectRootFolder)) - { - fileIoBase->SetAlias("@projectcache@", pathAliases.c_str()); - } pathAliases.clear(); if (m_settingsRegistry->Get(pathAliases.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder)) { - fileIoBase->SetAlias("@assets@", pathAliases.c_str()); - fileIoBase->SetAlias("@projectplatformcache@", pathAliases.c_str()); - fileIoBase->SetAlias("@root@", pathAliases.c_str()); // Deprecated Use @projectplatformcache@ + fileIoBase->SetAlias("@products@", pathAliases.c_str()); } pathAliases.clear(); if (m_settingsRegistry->Get(pathAliases.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder)) { fileIoBase->SetAlias("@engroot@", pathAliases.c_str()); - fileIoBase->SetAlias("@devroot@", pathAliases.c_str()); // Deprecated - Use @engroot@ } pathAliases.clear(); if (m_settingsRegistry->Get(pathAliases.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath)) { - fileIoBase->SetAlias("@devassets@", pathAliases.c_str()); // Deprecated - Use @projectsourceassets@ fileIoBase->SetAlias("@projectroot@", pathAliases.c_str()); - fileIoBase->SetAlias("@projectsourceassets@", (pathAliases / "Assets").c_str()); } } @@ -663,6 +719,15 @@ namespace AzFramework } fileIoBase->SetAlias("@log@", projectLogPath.c_str()); fileIoBase->CreatePath(projectLogPath.c_str()); + + DeprecatedAliasesKeyVisitor visitor; + if (m_settingsRegistry->Visit(visitor, ApplicationInternal::DeprecatedFileIOAliasesRoot)) + { + for (const auto& [oldAlias, newAlias] : visitor.m_aliases) + { + fileIoBase->SetDeprecatedAlias(oldAlias, newAlias); + } + } } } diff --git a/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp b/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp index 8064ba6669..e5a42aabbc 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp +++ b/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp @@ -1121,7 +1121,7 @@ namespace AZ::IO if (AZ::IO::FixedMaxPath pathBindRoot; !AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(pathBindRoot, szBindRoot)) { - AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(pathBindRoot, "@assets@"); + AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(pathBindRoot, "@products@"); desc.m_pathBindRoot = pathBindRoot.LexicallyNormal().String(); } else @@ -1807,9 +1807,9 @@ namespace AZ::IO if (m_eRecordFileOpenList != IArchive::RFOM_Disabled) { // we only want to record ASSET access - // assets are identified as files that are relative to the resolved @assets@ alias path + // assets are identified as files that are relative to the resolved @products@ alias path auto fileIoBase = AZ::IO::FileIOBase::GetInstance(); - const char* aliasValue = fileIoBase->GetAlias("@assets@"); + const char* aliasValue = fileIoBase->GetAlias("@products@"); if (AZ::IO::FixedMaxPath resolvedFilePath; fileIoBase->ResolvePath(resolvedFilePath, szFilename) diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFileIO.cpp b/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFileIO.cpp index 85ce0b6f9a..9e6e1034ea 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFileIO.cpp +++ b/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFileIO.cpp @@ -546,6 +546,16 @@ namespace AZ::IO realUnderlyingFileIO->GetAlias(alias); } + void ArchiveFileIO::SetDeprecatedAlias(AZStd::string_view oldAlias, AZStd::string_view newAlias) + { + FileIOBase* realUnderlyingFileIO = FileIOBase::GetDirectInstance(); + if (!realUnderlyingFileIO) + { + return; + } + realUnderlyingFileIO->SetDeprecatedAlias(oldAlias, newAlias); + } + AZStd::optional ArchiveFileIO::ConvertToAlias(char* inOutBuffer, AZ::u64 bufferLength) const { if ((!inOutBuffer) || (bufferLength == 0)) diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFileIO.h b/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFileIO.h index 21cef18a7a..7fd4e15e3a 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFileIO.h +++ b/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFileIO.h @@ -63,6 +63,7 @@ namespace AZ::IO IO::Result FindFiles(const char* filePath, const char* filter, FindFilesCallbackType callback) override; void SetAlias(const char* alias, const char* path) override; void ClearAlias(const char* alias) override; + void SetDeprecatedAlias(AZStd::string_view oldAlias, AZStd::string_view newAlias) override; AZStd::optional ConvertToAlias(char* inOutBuffer, AZ::u64 bufferLength) const override; bool ConvertToAlias(AZ::IO::FixedMaxPath& convertedPath, const AZ::IO::PathView& path) const override; using FileIOBase::ConvertToAlias; diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFindData.cpp b/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFindData.cpp index d7a92efbf6..7b483dc5de 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFindData.cpp +++ b/Code/Framework/AzFramework/AzFramework/Archive/ArchiveFindData.cpp @@ -186,8 +186,8 @@ namespace AZ::IO { // filter out the stuff which does not match. - // the problem here is that szDir might be something like "@assets@/levels/*" - // but our archive might be mounted at the root, or at some other folder at like "@assets@" or "@assets@/levels/mylevel" + // the problem here is that szDir might be something like "@products@/levels/*" + // but our archive might be mounted at the root, or at some other folder at like "@products@" or "@products@/levels/mylevel" // so there's really no way to filter out opening the pack and looking at the files inside. // however, the bind root is not part of the inner zip entry name either // and the ZipDir::FindFile actually expects just the chopped off piece. @@ -202,22 +202,22 @@ namespace AZ::IO // Example: - // "@assets@\\levels\\*" <--- szDir - // "@assets@\\" <--- mount point + // "@products@\\levels\\*" <--- szDir + // "@products@\\" <--- mount point // ~~~~~~~~~~~ Common part // "levels\\*" <---- remainder that is not in common // "" <--- mount point remainder. In this case, we should scan the contents of the pak for the remainder // Example: - // "@assets@\\levels\\*" <--- szDir - // "@assets@\\levels\\mylevel\\" <--- mount point (its level.pak) + // "@products@\\levels\\*" <--- szDir + // "@products@\\levels\\mylevel\\" <--- mount point (its level.pak) // ~~~~~~~~~~~~~~~~~~ common part // "*" <---- remainder that is not in common // "mylevel\\" <--- mount point remainder. // example: - // "@assets@\\levels\\otherlevel\\*" <--- szDir - // "@assets@\\levels\\mylevel\\" <--- mount point (its level.pak) + // "@products@\\levels\\otherlevel\\*" <--- szDir + // "@products@\\levels\\mylevel\\" <--- mount point (its level.pak) // "otherlevel\\*" <---- remainder // "mylevel\\" <--- mount point remainder. @@ -249,7 +249,7 @@ namespace AZ::IO // which means we may search inside the pack. ScanInZip(it->pZip.get(), sourcePathRemainder.Native()); } - + } } diff --git a/Code/Framework/AzFramework/AzFramework/Archive/MissingFileReport.cpp b/Code/Framework/AzFramework/AzFramework/Archive/MissingFileReport.cpp index 0a6116d313..4c6ed0363e 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/MissingFileReport.cpp +++ b/Code/Framework/AzFramework/AzFramework/Archive/MissingFileReport.cpp @@ -94,7 +94,7 @@ namespace AZ::IO::Internal } AZStd::smatch matches; - const AZStd::regex lodRegex("@assets@\\\\(.*)_lod[0-9]+(\\.cgfm?)"); + const AZStd::regex lodRegex("@products@\\\\(.*)_lod[0-9]+(\\.cgfm?)"); if (!AZStd::regex_match(szPath, matches, lodRegex) || matches.size() != 3) { // The current file is not a valid LOD file diff --git a/Code/Framework/AzFramework/AzFramework/Asset/AssetCatalog.cpp b/Code/Framework/AzFramework/AzFramework/Asset/AssetCatalog.cpp index 9b1946701c..e6b8211c28 100644 --- a/Code/Framework/AzFramework/AzFramework/Asset/AssetCatalog.cpp +++ b/Code/Framework/AzFramework/AzFramework/Asset/AssetCatalog.cpp @@ -725,7 +725,7 @@ namespace AzFramework if (!info.m_relativePath.empty()) { - const char* devAssetRoot = fileIO->GetAlias("@devassets@"); + const char* devAssetRoot = fileIO->GetAlias("@projectroot@"); if (devAssetRoot) { AZ::Data::AssetStreamInfo streamInfo; diff --git a/Code/Framework/AzFramework/AzFramework/Gem/GemInfo.cpp b/Code/Framework/AzFramework/AzFramework/Gem/GemInfo.cpp index a7c6b18061..cc31df3dbc 100644 --- a/Code/Framework/AzFramework/AzFramework/Gem/GemInfo.cpp +++ b/Code/Framework/AzFramework/AzFramework/Gem/GemInfo.cpp @@ -61,7 +61,7 @@ namespace AzFramework AZ::IO::Path& gemAbsPath = gemInfo.m_absoluteSourcePaths.emplace_back(value); // Resolve any file aliases first - Do not use ResolvePath() as that assumes - // any relative path is underneath the @assets@ alias + // any relative path is underneath the @products@ alias if (auto fileIoBase = AZ::IO::FileIOBase::GetInstance(); fileIoBase != nullptr) { AZ::IO::FixedMaxPath replacedAliasPath; diff --git a/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.cpp b/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.cpp index 49e16dcb90..c1b9c941bc 100644 --- a/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.cpp +++ b/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.cpp @@ -12,10 +12,12 @@ #include #include #include +#include #include #include #include #include +#include #include namespace AZ @@ -292,7 +294,7 @@ namespace AZ void LocalFileIO::CheckInvalidWrite([[maybe_unused]] const char* path) { #if defined(AZ_ENABLE_TRACING) - const char* assetAliasPath = GetAlias("@assets@"); + const char* assetAliasPath = GetAlias("@products@"); if (path && assetAliasPath) { const AZ::IO::PathView pathView(path); @@ -478,17 +480,15 @@ namespace AZ return false; } - if (IsAbsolutePath(path)) + if (AZ::IO::PathView(path).HasRootPath()) { size_t pathLen = strlen(path); if (pathLen + 1 < resolvedPathSize) { azstrncpy(resolvedPath, resolvedPathSize, path, pathLen + 1); - //see if the absolute path uses @assets@ or @root@, if it does lowercase the relative part - [[maybe_unused]] bool lowercasePath = LowerIfBeginsWith(resolvedPath, resolvedPathSize, GetAlias("@assets@")) - || LowerIfBeginsWith(resolvedPath, resolvedPathSize, GetAlias("@root@")) - || LowerIfBeginsWith(resolvedPath, resolvedPathSize, GetAlias("@projectplatformcache@")); + //see if the absolute path matches the resolved value of @products@, if it does lowercase the relative part + LowerIfBeginsWith(resolvedPath, resolvedPathSize, GetAlias("@products@")); ToUnixSlashes(resolvedPath, resolvedPathSize); return true; @@ -499,34 +499,39 @@ namespace AZ } } - char rootedPathBuffer[AZ_MAX_PATH_LEN] = {0}; + constexpr AZStd::string_view productAssetAlias = "@products@"; + // Add plus one for the path separator: / + constexpr size_t MaxPathSizeWithProductAssetAlias = AZ::IO::MaxPathLength + productAssetAlias.size() + 1; + using RootedPathString = AZStd::fixed_string; + RootedPathString rootedPathBuffer; const char* rootedPath = path; - // if the path does not begin with an alias, then it is assumed to begin with @assets@ + // if the path does not begin with an alias, then it is assumed to begin with @products@ if (path[0] != '@') { - if (GetAlias("@assets@")) + if (GetAlias("@products@")) { - const int rootLength = 9;// strlen("@assets@/") - azstrncpy(rootedPathBuffer, AZ_MAX_PATH_LEN, "@assets@/", rootLength); - size_t pathLen = strlen(path); - size_t rootedPathBufferlength = rootLength + pathLen + 1;// +1 for null terminator - if (rootedPathBufferlength > resolvedPathSize) + + if (const size_t requiredSize = productAssetAlias.size() + strlen(path) + 1; + requiredSize > rootedPathBuffer.capacity()) { - AZ_Assert(rootedPathBufferlength < resolvedPathSize, "Constructed path length is wrong:%s", rootedPathBuffer);//path constructed is wrong - size_t remainingSize = resolvedPathSize - rootLength - 1;// - 1 for null terminator - azstrncpy(rootedPathBuffer + rootLength, AZ_MAX_PATH_LEN, path, remainingSize); - rootedPathBuffer[resolvedPathSize - 1] = '\0'; + AZ_Error("FileIO", false, "Prepending the %.*s alias to the input path results in a path longer than the" + " AZ::IO::MaxPathLength + the alias size of %zu. The size of the potential failed path is %zu", + AZ_STRING_ARG(productAssetAlias), rootedPathBuffer.capacity(), requiredSize) } else { - azstrncpy(rootedPathBuffer + rootLength, AZ_MAX_PATH_LEN - rootLength, path, pathLen + 1); + rootedPathBuffer = RootedPathString::format("%.*s/%s", AZ_STRING_ARG(productAssetAlias), path); } } else { - ConvertToAbsolutePath(path, rootedPathBuffer, AZ_MAX_PATH_LEN); + if (ConvertToAbsolutePath(path, rootedPathBuffer.data(), rootedPathBuffer.capacity())) + { + // Recalculate the internal string length + rootedPathBuffer.resize_no_construct(AZStd::char_traits::length(rootedPathBuffer.data())); + } } - rootedPath = rootedPathBuffer; + rootedPath = rootedPathBuffer.c_str(); } if (ResolveAliases(rootedPath, resolvedPath, resolvedPathSize)) @@ -561,11 +566,57 @@ namespace AZ const char* LocalFileIO::GetAlias(const char* key) const { - const auto it = m_aliases.find(key); - if (it != m_aliases.end()) + if (const auto it = m_aliases.find(key); it != m_aliases.end()) { return it->second.c_str(); } + else if (const auto deprecatedIt = m_deprecatedAliases.find(key); + deprecatedIt != m_deprecatedAliases.end()) + { + AZ_Error("FileIO", false, R"(Alias "%s" is deprecated. Please use alias "%s" instead)", + key, deprecatedIt->second.c_str()); + AZStd::string_view aliasValue = deprecatedIt->second; + // Contains the list of aliases resolved so far + // If max_size is hit, than an error is logged and nullptr is returned + using VisitedAliasSet = AZStd::fixed_unordered_set; + VisitedAliasSet visitedAliasSet; + while (aliasValue.starts_with("@")) + { + if (visitedAliasSet.contains(aliasValue)) + { + AZ_Error("FileIO", false, "Cycle found with for alias %.*s when trying to resolve deprecated alias %s", + AZ_STRING_ARG(aliasValue), key); + return nullptr; + } + + if(visitedAliasSet.size() == visitedAliasSet.max_size()) + { + AZ_Error("FileIO", false, "Unable to resolve path to deprecated alias %s within %zu steps", + key, visitedAliasSet.max_size()); + return nullptr; + } + + // Add the current alias value to the visited set + visitedAliasSet.emplace(aliasValue); + + // Check if the alias value corresponds to another alias + if (auto resolvedIter = m_aliases.find(aliasValue); resolvedIter != m_aliases.end()) + { + aliasValue = resolvedIter->second; + } + else if (resolvedIter = m_deprecatedAliases.find(aliasValue); + resolvedIter != m_deprecatedAliases.end()) + { + aliasValue = resolvedIter->second; + } + else + { + return nullptr; + } + } + + return aliasValue.data(); + } return nullptr; } @@ -574,6 +625,11 @@ namespace AZ m_aliases.erase(key); } + void LocalFileIO::SetDeprecatedAlias(AZStd::string_view oldAlias, AZStd::string_view newAlias) + { + m_deprecatedAliases[oldAlias] = newAlias; + } + AZStd::optional LocalFileIO::ConvertToAliasBuffer(char* outBuffer, AZ::u64 outBufferLength, AZStd::string_view inBuffer) const { size_t longestMatch = 0; @@ -675,7 +731,9 @@ namespace AZ : string_view_pair{}; size_t requiredResolvedPathSize = pathView.size() - aliasKey.size() + aliasValue.size() + 1; - AZ_Assert(path != resolvedPath && resolvedPathSize >= requiredResolvedPathSize, "Resolved path is incorrect"); + AZ_Assert(path != resolvedPath, "ResolveAliases does not support inplace update of the path"); + AZ_Assert(resolvedPathSize >= requiredResolvedPathSize, "Resolved path size %llu not large enough. It needs to be %zu", + resolvedPathSize, requiredResolvedPathSize); // we assert above, but we also need to properly handle the case when the resolvedPath buffer size // is too small to copy the source into. if (path == resolvedPath || (resolvedPathSize < requiredResolvedPathSize)) @@ -699,13 +757,9 @@ namespace AZ resolvedPath[resolvedPathLen] = '\0'; // If the path started with one of the "asset cache" path aliases, lowercase the path - const char* assetAliasPath = GetAlias("@assets@"); - const char* rootAliasPath = GetAlias("@root@"); - const char* projectPlatformCacheAliasPath = GetAlias("@projectplatformcache@"); + const char* projectPlatformCacheAliasPath = GetAlias("@products@"); - const bool lowercasePath = (assetAliasPath != nullptr && AZ::StringFunc::StartsWith(resolvedPath, assetAliasPath)) || - (rootAliasPath != nullptr && AZ::StringFunc::StartsWith(resolvedPath, rootAliasPath)) || - (projectPlatformCacheAliasPath != nullptr && AZ::StringFunc::StartsWith(resolvedPath, projectPlatformCacheAliasPath)); + const bool lowercasePath = projectPlatformCacheAliasPath != nullptr && AZ::StringFunc::StartsWith(resolvedPath, projectPlatformCacheAliasPath); if (lowercasePath) { @@ -822,5 +876,10 @@ namespace AZ return pathStr + "/"; } + + bool LocalFileIO::ConvertToAbsolutePath(const char* path, char* absolutePath, AZ::u64 maxLength) const + { + return AZ::Utils::ConvertToAbsolutePath(path, absolutePath, maxLength); + } } // namespace IO } // namespace AZ diff --git a/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.h b/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.h index a9db55b320..a5ee1519a2 100644 --- a/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.h +++ b/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.h @@ -61,6 +61,8 @@ namespace AZ void SetAlias(const char* alias, const char* path) override; void ClearAlias(const char* alias) override; const char* GetAlias(const char* alias) const override; + void SetDeprecatedAlias(AZStd::string_view oldAlias, AZStd::string_view newAlias) override; + AZStd::optional ConvertToAlias(char* inOutBuffer, AZ::u64 bufferLength) const override; bool ConvertToAlias(AZ::IO::FixedMaxPath& convertedPath, const AZ::IO::PathView& path) const override; using FileIOBase::ConvertToAlias; @@ -71,7 +73,7 @@ namespace AZ bool GetFilename(HandleType fileHandle, char* filename, AZ::u64 filenameSize) const override; bool ConvertToAbsolutePath(const char* path, char* absolutePath, AZ::u64 maxLength) const; - + private: SystemFile* GetFilePointerFromHandle(HandleType fileHandle); @@ -79,7 +81,6 @@ namespace AZ AZStd::optional ConvertToAliasBuffer(char* outBuffer, AZ::u64 outBufferLength, AZStd::string_view inBuffer) const; bool ResolveAliases(const char* path, char* resolvedPath, AZ::u64 resolvedPathSize) const; - bool IsAbsolutePath(const char* path) const; bool LowerIfBeginsWith(char* inOutBuffer, AZ::u64 bufferLen, const char* alias) const; @@ -91,6 +92,7 @@ namespace AZ AZStd::atomic m_nextHandle; AZStd::unordered_map m_openFiles; AZStd::unordered_map m_aliases; + AZStd::unordered_map m_deprecatedAliases; void CheckInvalidWrite(const char* path); }; diff --git a/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.cpp b/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.cpp index 041e5baf4a..9e05cd5cb9 100644 --- a/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.cpp +++ b/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.cpp @@ -49,14 +49,14 @@ namespace AZ s_IOLog.append(m_name); s_IOLog.append("\r\n"); } - + void Append(const char* line) { s_IOLog.append(AZStd::string::format("%u ", m_fileOperation)); s_IOLog.append(line); s_IOLog.append("\r\n"); } - + ~LogCall() { s_IOLog.append(AZStd::string::format("%u End ", m_fileOperation)); @@ -251,7 +251,7 @@ namespace AZ REMOTEFILE_LOG_APPEND(AZStd::string::format("NetworkFileIO::Size(filePath=%s) size request failed. return Error", filePath).c_str()); return ResultCode::Error; } - + size = response.m_size; REMOTEFILE_LOG_APPEND(AZStd::string::format("NetworkFileIO::Size(filePath=%s) size=%u. return Success", filePath, size).c_str()); return ResultCode::Success; @@ -793,6 +793,12 @@ namespace AZ REMOTEFILE_LOG_CALL(AZStd::string::format("NetworkFileIO()::ClearAlias(alias=%s)", alias?alias:"nullptr").c_str()); } + void NetworkFileIO::SetDeprecatedAlias([[maybe_unused]] AZStd::string_view oldAlias, [[maybe_unused]] AZStd::string_view newAlias) + { + REMOTEFILE_LOG_CALL(AZStd::string::format("NetworkFileIO()::SetDeprecatedAlias(oldAlias=%.*s, newAlias=%.*s)", + AZ_STRING_ARG(oldAlias), AZ_STRING_ARG(newAlias)).c_str()); + } + AZStd::optional NetworkFileIO::ConvertToAlias(char* inOutBuffer, [[maybe_unused]] AZ::u64 bufferLength) const { REMOTEFILE_LOG_CALL(AZStd::string::format("NetworkFileIO()::ConvertToAlias(inOutBuffer=%s, bufferLength=%u)", inOutBuffer?inOutBuffer:"nullptr", bufferLength).c_str()); @@ -927,7 +933,7 @@ namespace AZ { m_cacheLookaheadPos = filePosition - CacheStartFilePosition(); } - + void RemoteFileCache::SyncCheck() { #ifdef REMOTEFILEIO_SYNC_CHECK @@ -955,7 +961,7 @@ namespace AZ AZ_TracePrintf(RemoteFileCacheChannel, "RemoteFileCache::SyncCheck(m_fileHandle=%u) tell request failed.", m_fileHandle); REMOTEFILE_LOG_APPEND(AZStd::string::format("RemoteFileCache::SyncCheck(m_fileHandle=%u) tell request failed.", m_fileHandle).c_str()); } - + if (responce.m_offset != m_filePosition) { AZ_TracePrintf(RemoteFileCacheChannel, "RemoteFileCache::SyncCheck(m_fileHandle=%u) failed!!! m_filePosition=%u tell=%u", m_fileHandle, m_filePosition, responce.m_offset); @@ -1028,7 +1034,7 @@ namespace AZ { REMOTEFILE_LOG_CALL(AZStd::string::format("RemoteFileIO()::Close(fileHandle=%u)", fileHandle).c_str()); Result returnValue = NetworkFileIO::Close(fileHandle); - + if (returnValue == ResultCode::Success) { AZStd::lock_guard lock(m_remoteFileCacheGuard); @@ -1160,7 +1166,7 @@ namespace AZ REMOTEFILE_LOG_CALL(AZStd::string::format("RemoteFileIO()::Read(fileHandle=%u, buffer=OUT, size=%u, failOnFewerThanSizeBytesRead=%s, bytesRead=OUT)", fileHandle, size, failOnFewerThanSizeBytesRead ? "True" : "False").c_str()); AZStd::lock_guard lock(m_remoteFileCacheGuard); RemoteFileCache& cache = GetCache(fileHandle); - + AZ::u64 remainingBytesToRead = size; AZ::u64 bytesReadFromCache = 0; AZ::u64 remainingBytesInCache = cache.RemainingBytes(); @@ -1263,7 +1269,7 @@ namespace AZ RemoteFileCache& cache = GetCache(fileHandle); if (cache.m_cacheLookaheadBuffer.size() && cache.RemainingBytes()) { - // find out where we are + // find out where we are AZ::u64 seekPosition = cache.CacheFilePosition(); // note, seeks are predicted, and do not ask for a response. @@ -1361,6 +1367,14 @@ namespace AZ } } + void RemoteFileIO::SetDeprecatedAlias(AZStd::string_view oldAlias, AZStd::string_view newAlias) + { + if (m_excludedFileIO) + { + m_excludedFileIO->SetDeprecatedAlias(oldAlias, newAlias); + } + } + AZStd::optional RemoteFileIO::ConvertToAlias(char* inOutBuffer, AZ::u64 bufferLength) const { return m_excludedFileIO ? m_excludedFileIO->ConvertToAlias(inOutBuffer, bufferLength) : strlen(inOutBuffer); diff --git a/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.h b/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.h index d91e59bebc..77e91e1978 100644 --- a/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.h +++ b/Code/Framework/AzFramework/AzFramework/IO/RemoteFileIO.h @@ -102,6 +102,7 @@ namespace AZ Result FindFiles(const char* filePath, const char* filter, FindFilesCallbackType callback) override; void SetAlias(const char* alias, const char* path) override; void ClearAlias(const char* alias) override; + void SetDeprecatedAlias(AZStd::string_view oldAlias, AZStd::string_view newAlias) override; AZStd::optional ConvertToAlias(char* inOutBuffer, AZ::u64 bufferLength) const override; bool ConvertToAlias(AZ::IO::FixedMaxPath& convertedPath, const AZ::IO::PathView& path) const override; using FileIOBase::ConvertToAlias; @@ -194,6 +195,7 @@ namespace AZ void SetAlias(const char* alias, const char* path) override; const char* GetAlias(const char* alias) const override; void ClearAlias(const char* alias) override; + void SetDeprecatedAlias(AZStd::string_view oldAlias, AZStd::string_view newAlias) override; AZStd::optional ConvertToAlias(char* inOutBuffer, AZ::u64 bufferLength) const override; bool ConvertToAlias(AZ::IO::FixedMaxPath& convertedPath, const AZ::IO::PathView& path) const override; using FileIOBase::ConvertToAlias; diff --git a/Code/Framework/AzFramework/Platform/Android/AzFramework/IO/LocalFileIO_Android.cpp b/Code/Framework/AzFramework/Platform/Android/AzFramework/IO/LocalFileIO_Android.cpp index b454755cd4..bd5ba39d76 100644 --- a/Code/Framework/AzFramework/Platform/Android/AzFramework/IO/LocalFileIO_Android.cpp +++ b/Code/Framework/AzFramework/Platform/Android/AzFramework/IO/LocalFileIO_Android.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include @@ -42,10 +41,10 @@ namespace AZ { Result LocalFileIO::Copy(const char* sourceFilePath, const char* destinationFilePath) { - char resolvedSourcePath[AZ_MAX_PATH_LEN]; - char resolvedDestPath[AZ_MAX_PATH_LEN]; - ResolvePath(sourceFilePath, resolvedSourcePath, AZ_MAX_PATH_LEN); - ResolvePath(destinationFilePath, resolvedDestPath, AZ_MAX_PATH_LEN); + char resolvedSourcePath[AZ::IO::MaxPathLength]; + char resolvedDestPath[AZ::IO::MaxPathLength]; + ResolvePath(sourceFilePath, resolvedSourcePath, AZ::IO::MaxPathLength); + ResolvePath(destinationFilePath, resolvedDestPath, AZ::IO::MaxPathLength); if (AZ::Android::Utils::IsApkPath(sourceFilePath) || AZ::Android::Utils::IsApkPath(destinationFilePath)) { @@ -77,18 +76,17 @@ namespace AZ { ANDROID_IO_PROFILE_SECTION_ARGS("FindFiles:%s", filePath); - char resolvedPath[AZ_MAX_PATH_LEN]; - ResolvePath(filePath, resolvedPath, AZ_MAX_PATH_LEN); + char resolvedPath[AZ::IO::MaxPathLength]; + ResolvePath(filePath, resolvedPath, AZ::IO::MaxPathLength); AZStd::string pathWithoutSlash = RemoveTrailingSlash(resolvedPath); bool isInAPK = AZ::Android::Utils::IsApkPath(pathWithoutSlash.c_str()); + AZ::IO::FixedMaxPath tempBuffer; if (isInAPK) { AZ::IO::FixedMaxPath strippedPath = AZ::Android::Utils::StripApkPrefix(pathWithoutSlash.c_str()); - char tempBuffer[AZ_MAX_PATH_LEN] = {0}; - AZ::Android::APKFileHandler::ParseDirectory(strippedPath.c_str(), [&](const char* name) { AZStd::string_view filenameView = name; @@ -98,10 +96,9 @@ namespace AZ AZStd::string foundFilePath = CheckForTrailingSlash(resolvedPath); foundFilePath += name; // if aliased, de-alias! - azstrcpy(tempBuffer, AZ_MAX_PATH_LEN, foundFilePath.c_str()); - ConvertToAlias(tempBuffer, AZ_MAX_PATH_LEN); + ConvertToAlias(tempBuffer, AZ::IO::PathView{ foundFilePath }); - if (!callback(tempBuffer)) + if (!callback(tempBuffer.c_str())) { return false; } @@ -115,10 +112,6 @@ namespace AZ if (dir != nullptr) { - // because the absolute path might actually be SHORTER than the alias ("c:/r/dev" -> "@devroot@"), we need to - // use a static buffer here. - char tempBuffer[AZ_MAX_PATH_LEN]; - // clear the errno state so we can distinguish between errors and end of stream errno = 0; struct dirent* entry = readdir(dir); @@ -133,10 +126,9 @@ namespace AZ AZStd::string foundFilePath = CheckForTrailingSlash(resolvedPath); foundFilePath += entry->d_name; // if aliased, de-alias! - azstrcpy(tempBuffer, AZ_MAX_PATH_LEN, foundFilePath.c_str()); - ConvertToAlias(tempBuffer, AZ_MAX_PATH_LEN); + ConvertToAlias(tempBuffer, AZ::IO::PathView{ foundFilePath }); - if (!callback(tempBuffer)) + if (!callback(tempBuffer.c_str())) { break; } @@ -163,8 +155,8 @@ namespace AZ Result LocalFileIO::CreatePath(const char* filePath) { - char resolvedPath[AZ_MAX_PATH_LEN]; - ResolvePath(filePath, resolvedPath, AZ_MAX_PATH_LEN); + char resolvedPath[AZ::IO::MaxPathLength]; + ResolvePath(filePath, resolvedPath, AZ::IO::MaxPathLength); if (AZ::Android::Utils::IsApkPath(resolvedPath)) { @@ -201,33 +193,5 @@ namespace AZ mkdir(pathBuffer.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); return IsDirectory(resolvedPath) ? ResultCode::Success : ResultCode::Error; } - - bool LocalFileIO::IsAbsolutePath(const char* path) const - { - return path && path[0] == '/'; - } - - bool LocalFileIO::ConvertToAbsolutePath(const char* path, char* absolutePath, AZ::u64 maxLength) const - { - if (AZ::Android::Utils::IsApkPath(path)) - { - azstrncpy(absolutePath, maxLength, path, maxLength); - return true; - } - AZ_Assert(maxLength >= AZ_MAX_PATH_LEN, "Path length is larger than AZ_MAX_PATH_LEN"); - if (!IsAbsolutePath(path)) - { - // note that realpath fails if the path does not exist and actually changes the return value - // to be the actual place that FAILED, which we don't want. - // if we fail, we'd prefer to fall through and at least use the original path. - const char* result = realpath(path, absolutePath); - if (result) - { - return true; - } - } - azstrcpy(absolutePath, maxLength, path); - return IsAbsolutePath(absolutePath); - } } // namespace IO }//namespace AZ diff --git a/Code/Framework/AzFramework/Platform/Common/UnixLike/AzFramework/IO/LocalFileIO_UnixLike.cpp b/Code/Framework/AzFramework/Platform/Common/UnixLike/AzFramework/IO/LocalFileIO_UnixLike.cpp index 844464681a..cbcf4a3f56 100644 --- a/Code/Framework/AzFramework/Platform/Common/UnixLike/AzFramework/IO/LocalFileIO_UnixLike.cpp +++ b/Code/Framework/AzFramework/Platform/Common/UnixLike/AzFramework/IO/LocalFileIO_UnixLike.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include namespace AZ @@ -19,11 +19,11 @@ namespace AZ { Result LocalFileIO::Copy(const char* sourceFilePath, const char* destinationFilePath) { - char resolvedSourceFilePath[AZ_MAX_PATH_LEN] = {0}; - ResolvePath(sourceFilePath, resolvedSourceFilePath, AZ_MAX_PATH_LEN); + char resolvedSourceFilePath[AZ::IO::MaxPathLength] = {0}; + ResolvePath(sourceFilePath, resolvedSourceFilePath, AZ::IO::MaxPathLength); - char resolvedDestinationFilePath[AZ_MAX_PATH_LEN] = {0}; - ResolvePath(destinationFilePath, resolvedDestinationFilePath, AZ_MAX_PATH_LEN); + char resolvedDestinationFilePath[AZ::IO::MaxPathLength] = {0}; + ResolvePath(destinationFilePath, resolvedDestinationFilePath, AZ::IO::MaxPathLength); // Use standard C++ method of file copy. { @@ -45,17 +45,15 @@ namespace AZ Result LocalFileIO::FindFiles(const char* filePath, const char* filter, FindFilesCallbackType callback) { - char resolvedPath[AZ_MAX_PATH_LEN] = {0}; - ResolvePath(filePath, resolvedPath, AZ_MAX_PATH_LEN); + char resolvedPath[AZ::IO::MaxPathLength] = {0}; + ResolvePath(filePath, resolvedPath, AZ::IO::MaxPathLength); AZStd::string withoutSlash = RemoveTrailingSlash(resolvedPath); DIR* dir = opendir(withoutSlash.c_str()); if (dir != nullptr) { - // because the absolute path might actually be SHORTER than the alias ("c:/r/dev" -> "@devroot@"), we need to - // use a static buffer here. - char tempBuffer[AZ_MAX_PATH_LEN]; + AZ::IO::FixedMaxPath tempBuffer; errno = 0; struct dirent* entry = readdir(dir); @@ -70,10 +68,9 @@ namespace AZ AZStd::string foundFilePath = CheckForTrailingSlash(resolvedPath); foundFilePath += entry->d_name; // if aliased, dealias! - azstrcpy(tempBuffer, AZ_MAX_PATH_LEN, foundFilePath.c_str()); - ConvertToAlias(tempBuffer, AZ_MAX_PATH_LEN); + ConvertToAlias(tempBuffer, AZ::IO::PathView{ foundFilePath }); - if (!callback(tempBuffer)) + if (!callback(tempBuffer.c_str())) { break; } @@ -92,8 +89,8 @@ namespace AZ Result LocalFileIO::CreatePath(const char* filePath) { - char resolvedPath[AZ_MAX_PATH_LEN] = {0}; - ResolvePath(filePath, resolvedPath, AZ_MAX_PATH_LEN); + char resolvedPath[AZ::IO::MaxPathLength] = {0}; + ResolvePath(filePath, resolvedPath, AZ::IO::MaxPathLength); // create all paths up to that directory. // its not an error if the path exists. @@ -125,28 +122,5 @@ namespace AZ mkdir(buf.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); return IsDirectory(resolvedPath) ? ResultCode::Success : ResultCode::Error; } - - bool LocalFileIO::IsAbsolutePath(const char* path) const - { - return path && path[0] == '/'; - } - - bool LocalFileIO::ConvertToAbsolutePath(const char* path, char* absolutePath, AZ::u64 maxLength) const - { - AZ_Assert(maxLength >= AZ_MAX_PATH_LEN, "Path length is larger than AZ_MAX_PATH_LEN"); - if (!IsAbsolutePath(path)) - { - // note that realpath fails if the path does not exist and actually changes the return value - // to be the actual place that FAILED, which we don't want. - // if we fail, we'd prefer to fall through and at least use the original path. - const char* result = realpath(path, absolutePath); - if (result) - { - return true; - } - } - azstrcpy(absolutePath, maxLength, path); - return IsAbsolutePath(absolutePath); - } } // namespace IO } // namespace AZ diff --git a/Code/Framework/AzFramework/Platform/Common/WinAPI/AzFramework/IO/LocalFileIO_WinAPI.cpp b/Code/Framework/AzFramework/Platform/Common/WinAPI/AzFramework/IO/LocalFileIO_WinAPI.cpp index 64787d4951..7ff8a96c09 100644 --- a/Code/Framework/AzFramework/Platform/Common/WinAPI/AzFramework/IO/LocalFileIO_WinAPI.cpp +++ b/Code/Framework/AzFramework/Platform/Common/WinAPI/AzFramework/IO/LocalFileIO_WinAPI.cpp @@ -47,7 +47,7 @@ namespace AZ if (hFind != INVALID_HANDLE_VALUE) { - // because the absolute path might actually be SHORTER than the alias ("c:/r/dev" -> "@devroot@"), we need to + // because the absolute path might actually be SHORTER than the alias ("D:/o3de" -> "@engroot@"), we need to // use a static buffer here. char tempBuffer[AZ_MAX_PATH_LEN]; do @@ -133,36 +133,5 @@ namespace AZ return SystemFile::CreateDir(buf.c_str()) ? ResultCode::Success : ResultCode::Error; } - - bool LocalFileIO::ConvertToAbsolutePath(const char* path, char* absolutePath, AZ::u64 maxLength) const - { - char* result = _fullpath(absolutePath, path, maxLength); - size_t len = ::strlen(absolutePath); - if (len > 0) - { - // strip trailing slash - if (absolutePath[len - 1] == '/' || absolutePath[len - 1] == '\\') - { - absolutePath[len - 1] = 0; - } - - // For some reason, at least on windows, _fullpath returns a lowercase drive letter even though other systems like Qt, use upper case. - if (len > 2) - { - if (absolutePath[1] == ':') - { - absolutePath[0] = (char)toupper(absolutePath[0]); - } - } - } - return result != nullptr; - } - - bool LocalFileIO::IsAbsolutePath(const char* path) const - { - char drive[16] = { 0 }; - _splitpath_s(path, drive, 16, nullptr, 0, nullptr, 0, nullptr, 0); - return strlen(drive) > 0; - } } // namespace IO }//namespace AZ diff --git a/Code/Framework/AzFramework/Platform/Windows/AzFramework/IO/LocalFileIO_Windows.cpp b/Code/Framework/AzFramework/Platform/Windows/AzFramework/IO/LocalFileIO_Windows.cpp index b8f62a2b77..173ec61263 100644 --- a/Code/Framework/AzFramework/Platform/Windows/AzFramework/IO/LocalFileIO_Windows.cpp +++ b/Code/Framework/AzFramework/Platform/Windows/AzFramework/IO/LocalFileIO_Windows.cpp @@ -7,26 +7,24 @@ */ #include #include +#include +#include #include -namespace AZ +namespace AZ::IO { - namespace IO + Result LocalFileIO::Copy(const char* sourceFilePath, const char* destinationFilePath) { + AZ::IO::FixedMaxPath resolvedSourcePath; + ResolvePath(resolvedSourcePath, sourceFilePath); + AZ::IO::FixedMaxPath resolvedDestPath; + ResolvePath(resolvedDestPath, destinationFilePath); - Result LocalFileIO::Copy(const char* sourceFilePath, const char* destinationFilePath) - { - char resolvedSourcePath[AZ_MAX_PATH_LEN]; - ResolvePath(sourceFilePath, resolvedSourcePath, AZ_MAX_PATH_LEN); - char resolvedDestPath[AZ_MAX_PATH_LEN]; - ResolvePath(destinationFilePath, resolvedDestPath, AZ_MAX_PATH_LEN); + AZStd::fixed_wstring resolvedSourcePathW; + AZStd::fixed_wstring resolvedDestPathW; + AZStd::to_wstring(resolvedSourcePathW, resolvedSourcePath.Native()); + AZStd::to_wstring(resolvedDestPathW, resolvedDestPath.Native()); - if (::CopyFileA(resolvedSourcePath, resolvedDestPath, false) == 0) - { - return ResultCode::Error; - } - - return ResultCode::Success; - } - } // namespace IO -}//namespace AZ + return ::CopyFileW(resolvedSourcePathW.c_str(), resolvedDestPathW.c_str(), false) != 0 ? ResultCode::Success : ResultCode::Error; + } +}//namespace AZ::IO diff --git a/Code/Framework/AzFramework/Tests/Application.cpp b/Code/Framework/AzFramework/Tests/Application.cpp index 313b5e3b56..9ad072cba5 100644 --- a/Code/Framework/AzFramework/Tests/Application.cpp +++ b/Code/Framework/AzFramework/Tests/Application.cpp @@ -26,7 +26,7 @@ protected: } if (auto fileIoBase = AZ::IO::FileIOBase::GetInstance(); fileIoBase != nullptr) { - fileIoBase->SetAlias("@assets@", m_tempDirectory.GetDirectory()); + fileIoBase->SetAlias("@products@", m_tempDirectory.GetDirectory()); } } diff --git a/Code/Framework/AzFramework/Tests/ArchiveTests.cpp b/Code/Framework/AzFramework/Tests/ArchiveTests.cpp index 8e88ccfc39..37babb49a8 100644 --- a/Code/Framework/AzFramework/Tests/ArchiveTests.cpp +++ b/Code/Framework/AzFramework/Tests/ArchiveTests.cpp @@ -50,7 +50,7 @@ namespace UnitTest m_application->Start({}); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); } @@ -262,7 +262,7 @@ namespace UnitTest pArchive.reset(); EXPECT_TRUE(IsPackValid(testArchivePath_withSubfolders.c_str())); - EXPECT_TRUE(archive->OpenPack("@assets@", testArchivePath_withSubfolders.c_str())); + EXPECT_TRUE(archive->OpenPack("@products@", testArchivePath_withSubfolders.c_str())); EXPECT_TRUE(archive->IsFileExist(fileInArchiveFile)); } @@ -353,7 +353,7 @@ namespace UnitTest // and be able to IMMEDIATELY // * read the file in the subfolder // * enumerate the folders (including that subfolder) even though they are 'virtual', not real folders on physical media - // * all of the above even though the mount point for the archive is @assets@ wheras the physical pack lives in @usercache@ + // * all of the above even though the mount point for the archive is @products@ wheras the physical pack lives in @usercache@ // finally, we're going to repeat the above test but with files mounted with subfolders // so for example, the pack will contain levelinfo.xml at the root of it // but it will be mounted at a subfolder (levels/mylevel). @@ -388,7 +388,7 @@ namespace UnitTest pArchive.reset(); EXPECT_TRUE(IsPackValid(testArchivePath_withSubfolders)); - EXPECT_TRUE(archive->OpenPack("@assets@", testArchivePath_withSubfolders)); + EXPECT_TRUE(archive->OpenPack("@products@", testArchivePath_withSubfolders)); // ---- BARRAGE OF TESTS EXPECT_TRUE(archive->IsFileExist("levels\\mylevel\\levelinfo.xml")); EXPECT_TRUE(archive->IsFileExist("levels//mylevel//levelinfo.xml")); @@ -484,7 +484,7 @@ namespace UnitTest pArchive.reset(); EXPECT_TRUE(IsPackValid(testArchivePath_withMountPoint)); - EXPECT_TRUE(archive->OpenPack("@assets@\\uniquename\\mylevel2", testArchivePath_withMountPoint)); + EXPECT_TRUE(archive->OpenPack("@products@\\uniquename\\mylevel2", testArchivePath_withMountPoint)); // ---- BARRAGE OF TESTS EXPECT_TRUE(archive->IsFileExist("uniquename\\mylevel2\\levelinfo.xml")); @@ -543,7 +543,7 @@ namespace UnitTest archive->ClosePack(testArchivePath_withMountPoint); // --- test to make sure that when you iterate only the first component is found, so bury it deep and ask for the root - EXPECT_TRUE(archive->OpenPack("@assets@\\uniquename\\mylevel2\\mylevel3\\mylevel4", testArchivePath_withMountPoint)); + EXPECT_TRUE(archive->OpenPack("@products@\\uniquename\\mylevel2\\mylevel3\\mylevel4", testArchivePath_withMountPoint)); found_mylevel_folder = false; handle = archive->FindFirst("uniquename\\*"); @@ -574,9 +574,9 @@ namespace UnitTest found_mylevel_folder = false; // now make sure no red herrings appear - // for example, if a file is mounted at "@assets@\\uniquename\\mylevel2\\mylevel3\\mylevel4" - // and the file "@assets@\\somethingelse" is requested it should not be found - // in addition if the file "@assets@\\uniquename\\mylevel3" is requested it should not be found + // for example, if a file is mounted at "@products@\\uniquename\\mylevel2\\mylevel3\\mylevel4" + // and the file "@products@\\somethingelse" is requested it should not be found + // in addition if the file "@products@\\uniquename\\mylevel3" is requested it should not be found handle = archive->FindFirst("somethingelse\\*"); EXPECT_FALSE(static_cast(handle)); @@ -610,7 +610,7 @@ namespace UnitTest cpfio.Remove(genericArchiveFileName); // create the asset alias directory - cpfio.CreatePath("@assets@"); + cpfio.CreatePath("@products@"); // create generic file @@ -635,11 +635,11 @@ namespace UnitTest pArchive.reset(); EXPECT_TRUE(IsPackValid(genericArchiveFileName)); - EXPECT_TRUE(archive->OpenPack("@assets@", genericArchiveFileName)); + EXPECT_TRUE(archive->OpenPack("@products@", genericArchiveFileName)); // ---- BARRAGE OF TESTS EXPECT_TRUE(cpfio.Exists("testfile.xml")); - EXPECT_TRUE(cpfio.Exists("@assets@/testfile.xml")); // this should be hte same file + EXPECT_TRUE(cpfio.Exists("@products@/testfile.xml")); // this should be hte same file EXPECT_TRUE(!cpfio.Exists("@log@/testfile.xml")); EXPECT_TRUE(!cpfio.Exists("@usercache@/testfile.xml")); EXPECT_TRUE(cpfio.Exists("@log@/unittesttemp/realfileforunittest.xml")); @@ -685,9 +685,9 @@ namespace UnitTest EXPECT_EQ(ResultCode::Success, cpfio.Close(normalFileHandle)); EXPECT_TRUE(!cpfio.IsDirectory("testfile.xml")); - EXPECT_TRUE(cpfio.IsDirectory("@assets@")); + EXPECT_TRUE(cpfio.IsDirectory("@products@")); EXPECT_TRUE(cpfio.IsReadOnly("testfile.xml")); - EXPECT_TRUE(cpfio.IsReadOnly("@assets@/testfile.xml")); + EXPECT_TRUE(cpfio.IsReadOnly("@products@/testfile.xml")); EXPECT_TRUE(!cpfio.IsReadOnly("@log@/unittesttemp/realfileforunittest.xml")); @@ -714,10 +714,10 @@ namespace UnitTest // find files test. AZ::IO::FixedMaxPath resolvedTestFilePath; - EXPECT_TRUE(cpfio.ResolvePath(resolvedTestFilePath, AZ::IO::PathView("@assets@/testfile.xml"))); + EXPECT_TRUE(cpfio.ResolvePath(resolvedTestFilePath, AZ::IO::PathView("@products@/testfile.xml"))); bool foundIt = false; // note that this file exists only in the archive. - cpfio.FindFiles("@assets@", "*.xml", [&foundIt, &cpfio, &resolvedTestFilePath](const char* foundName) + cpfio.FindFiles("@products@", "*.xml", [&foundIt, &cpfio, &resolvedTestFilePath](const char* foundName) { AZ::IO::FixedMaxPath resolvedFoundPath; EXPECT_TRUE(cpfio.ResolvePath(resolvedFoundPath, AZ::IO::PathView(foundName))); @@ -734,10 +734,10 @@ namespace UnitTest // The following test is disabled because it will trigger an AZ_ERROR which will affect the outcome of this entire test - // EXPECT_NE(ResultCode::Success, cpfio.Remove("@assets@/testfile.xml")); // may not delete archive files + // EXPECT_NE(ResultCode::Success, cpfio.Remove("@products@/testfile.xml")); // may not delete archive files // make sure it works with and without alias: - EXPECT_TRUE(cpfio.Exists("@assets@/testfile.xml")); + EXPECT_TRUE(cpfio.Exists("@products@/testfile.xml")); EXPECT_TRUE(cpfio.Exists("testfile.xml")); EXPECT_TRUE(cpfio.Exists("@log@/unittesttemp/realfileforunittest.xml")); @@ -788,22 +788,22 @@ namespace UnitTest EXPECT_TRUE(archive->ClosePack(realNameBuf)); // change its actual location: - EXPECT_TRUE(archive->OpenPack("@assets@", realNameBuf)); - EXPECT_TRUE(archive->IsFileExist("@assets@/foundit.dat")); + EXPECT_TRUE(archive->OpenPack("@products@", realNameBuf)); + EXPECT_TRUE(archive->IsFileExist("@products@/foundit.dat")); EXPECT_FALSE(archive->IsFileExist("@usercache@/foundit.dat")); // do not find it in the previous location! - EXPECT_FALSE(archive->IsFileExist("@assets@/foundit.dat", AZ::IO::IArchive::eFileLocation_OnDisk)); - EXPECT_FALSE(archive->IsFileExist("@assets@/notfoundit.dat")); + EXPECT_FALSE(archive->IsFileExist("@products@/foundit.dat", AZ::IO::IArchive::eFileLocation_OnDisk)); + EXPECT_FALSE(archive->IsFileExist("@products@/notfoundit.dat")); EXPECT_TRUE(archive->ClosePack(realNameBuf)); // try sub-folders - EXPECT_TRUE(archive->OpenPack("@assets@/mystuff", realNameBuf)); - EXPECT_TRUE(archive->IsFileExist("@assets@/mystuff/foundit.dat")); - EXPECT_FALSE(archive->IsFileExist("@assets@/foundit.dat")); // do not find it in the previous locations! + EXPECT_TRUE(archive->OpenPack("@products@/mystuff", realNameBuf)); + EXPECT_TRUE(archive->IsFileExist("@products@/mystuff/foundit.dat")); + EXPECT_FALSE(archive->IsFileExist("@products@/foundit.dat")); // do not find it in the previous locations! EXPECT_FALSE(archive->IsFileExist("@usercache@/foundit.dat")); // do not find it in the previous locations! - EXPECT_FALSE(archive->IsFileExist("@assets@/foundit.dat", AZ::IO::IArchive::eFileLocation_OnDisk)); - EXPECT_FALSE(archive->IsFileExist("@assets@/mystuff/foundit.dat", AZ::IO::IArchive::eFileLocation_OnDisk)); - EXPECT_FALSE(archive->IsFileExist("@assets@/notfoundit.dat")); // non-existent file - EXPECT_FALSE(archive->IsFileExist("@assets@/mystuff/notfoundit.dat")); // non-existent file + EXPECT_FALSE(archive->IsFileExist("@products@/foundit.dat", AZ::IO::IArchive::eFileLocation_OnDisk)); + EXPECT_FALSE(archive->IsFileExist("@products@/mystuff/foundit.dat", AZ::IO::IArchive::eFileLocation_OnDisk)); + EXPECT_FALSE(archive->IsFileExist("@products@/notfoundit.dat")); // non-existent file + EXPECT_FALSE(archive->IsFileExist("@products@/mystuff/notfoundit.dat")); // non-existent file EXPECT_TRUE(archive->ClosePack(realNameBuf)); } @@ -861,7 +861,7 @@ namespace UnitTest AZ::IO::FileIOBase* ioBase = AZ::IO::FileIOBase::GetInstance(); ASSERT_NE(nullptr, ioBase); - const char* assetsPath = ioBase->GetAlias("@assets@"); + const char* assetsPath = ioBase->GetAlias("@products@"); ASSERT_NE(nullptr, assetsPath); auto stringToAdd = AZ::IO::Path(assetsPath) / "textures" / "test.dds"; @@ -872,7 +872,7 @@ namespace UnitTest // it normalizes the string, so the slashes flip and everything is lowercased. AZ::IO::FixedMaxPath resolvedAddedPath; AZ::IO::FixedMaxPath resolvedResourcePath; - EXPECT_TRUE(ioBase->ReplaceAlias(resolvedAddedPath, "@assets@/textures/test.dds")); + EXPECT_TRUE(ioBase->ReplaceAlias(resolvedAddedPath, "@products@/textures/test.dds")); EXPECT_TRUE(ioBase->ReplaceAlias(resolvedResourcePath, reslist->GetFirst())); EXPECT_EQ(resolvedAddedPath, resolvedResourcePath); reslist->Clear(); diff --git a/Code/Framework/AzFramework/Tests/FileIO.cpp b/Code/Framework/AzFramework/Tests/FileIO.cpp index dbee109978..ca7c46b66c 100644 --- a/Code/Framework/AzFramework/Tests/FileIO.cpp +++ b/Code/Framework/AzFramework/Tests/FileIO.cpp @@ -802,6 +802,51 @@ namespace UnitTest AZ_TEST_STOP_TRACE_SUPPRESSION(1); } + TEST_F(AliasTest, GetAlias_LogsError_WhenAccessingDeprecatedAlias_Succeeds) + { + AZ::IO::LocalFileIO local; + + AZ::IO::FixedMaxPathString aliasFolder; + EXPECT_TRUE(local.ConvertToAbsolutePath("/temp", aliasFolder.data(), aliasFolder.capacity())); + aliasFolder.resize_no_construct(AZStd::char_traits::length(aliasFolder.data())); + + local.SetAlias("@test@", aliasFolder.c_str()); + local.SetDeprecatedAlias("@deprecated@", "@test@"); + local.SetDeprecatedAlias("@deprecatednonexistent@", "@nonexistent@"); + local.SetDeprecatedAlias("@deprecatedsecond@", "@deprecated@"); + local.SetDeprecatedAlias("@deprecatednonaliaspath@", aliasFolder); + + AZ_TEST_START_TRACE_SUPPRESSION; + const char* testAlias = local.GetAlias("@test@"); + ASSERT_NE(nullptr, testAlias); + EXPECT_EQ(AZ::IO::PathView(aliasFolder), AZ::IO::PathView(testAlias)); + AZ_TEST_STOP_TRACE_SUPPRESSION(0); + + // Validate that accessing Deprecated Alias results in AZ_Error + AZ_TEST_START_TRACE_SUPPRESSION; + testAlias = local.GetAlias("@deprecated@"); + ASSERT_NE(nullptr, testAlias); + EXPECT_EQ(AZ::IO::PathView(aliasFolder), AZ::IO::PathView(testAlias)); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + + AZ_TEST_START_TRACE_SUPPRESSION; + testAlias = local.GetAlias("@deprecatednonexistent@"); + EXPECT_EQ(nullptr, testAlias); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + + AZ_TEST_START_TRACE_SUPPRESSION; + testAlias = local.GetAlias("@deprecatedsecond@"); + ASSERT_NE(nullptr, testAlias); + EXPECT_EQ(AZ::IO::PathView(aliasFolder), AZ::IO::PathView(testAlias)); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + + AZ_TEST_START_TRACE_SUPPRESSION; + testAlias = local.GetAlias("@deprecatednonaliaspath@"); + ASSERT_NE(nullptr, testAlias); + EXPECT_EQ(AZ::IO::PathView(aliasFolder), AZ::IO::PathView(testAlias)); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + } + class SmartMoveTests : public FolderFixture { diff --git a/Code/Framework/AzFramework/Tests/FileTagTests.cpp b/Code/Framework/AzFramework/Tests/FileTagTests.cpp index 134e7aad6d..2b09a5638c 100644 --- a/Code/Framework/AzFramework/Tests/FileTagTests.cpp +++ b/Code/Framework/AzFramework/Tests/FileTagTests.cpp @@ -27,7 +27,7 @@ namespace UnitTest const char DummyFile[] = "dummy.txt"; const char AnotherDummyFile[] = "Foo/Dummy.txt"; - + const char DummyPattern[] = R"(^(.+)_([a-z]+)\..+$)"; const char MatchingPatternFile[] = "Foo/dummy_abc.txt"; const char NonMatchingPatternFile[] = "Foo/dummy_a8c.txt"; @@ -75,7 +75,7 @@ namespace UnitTest : public AllocatorsFixture { public: - + void SetUp() override { AllocatorsFixture::SetUp(); @@ -89,7 +89,7 @@ namespace UnitTest const char* testAssetRoot = m_tempDirectory.GetDirectory(); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); @@ -98,7 +98,7 @@ namespace UnitTest AZ::IO::FileIOBase::SetInstance(nullptr); AZ::IO::FileIOBase::SetInstance(m_data->m_localFileIO.get()); - AZ::IO::FileIOBase::GetInstance()->SetAlias("@assets@", testAssetRoot); + AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", testAssetRoot); m_data->m_excludeFileQueryManager = AZStd::make_unique(FileTagType::Exclude); m_data->m_includeFileQueryManager = AZStd::make_unique(FileTagType::Include); @@ -114,7 +114,7 @@ namespace UnitTest AZStd::vector includedWildcardTags = { DummyFileTags[DummyFileTagIndex::GIdx] }; EXPECT_TRUE(m_data->m_fileTagManager.AddFilePatternTags(DummyWildcard, FilePatternType::Wildcard, FileTagType::Include, includedWildcardTags).IsSuccess()); - + AzFramework::StringFunc::Path::Join(testAssetRoot, AZStd::string::format("%s.%s", ExcludeFile, FileTagAsset::Extension()).c_str(), m_data->m_excludeFile); AzFramework::StringFunc::Path::Join(testAssetRoot, AZStd::string::format("%s.%s", IncludeFile, FileTagAsset::Extension()).c_str(), m_data->m_includeFile); @@ -184,7 +184,7 @@ namespace UnitTest TEST_F(FileTagTest, FileTags_QueryByAbsoluteFilePath_Valid) { AZStd::string absoluteDummyFilePath = DummyFile; - EXPECT_TRUE(AzFramework::StringFunc::AssetDatabasePath::Join("@assets@", absoluteDummyFilePath.c_str(), absoluteDummyFilePath)); + EXPECT_TRUE(AzFramework::StringFunc::AssetDatabasePath::Join("@products@", absoluteDummyFilePath.c_str(), absoluteDummyFilePath)); AZStd::set tags = m_data->m_excludeFileQueryManager->GetTags(absoluteDummyFilePath); @@ -196,7 +196,7 @@ namespace UnitTest ASSERT_EQ(tags.size(), 0); AZStd::string absoluteAnotherDummyFilePath = AnotherDummyFile; - EXPECT_TRUE(AzFramework::StringFunc::AssetDatabasePath::Join("@assets@", absoluteAnotherDummyFilePath.c_str(), absoluteAnotherDummyFilePath)); + EXPECT_TRUE(AzFramework::StringFunc::AssetDatabasePath::Join("@products@", absoluteAnotherDummyFilePath.c_str(), absoluteAnotherDummyFilePath)); tags = m_data->m_includeFileQueryManager->GetTags(absoluteAnotherDummyFilePath); ASSERT_EQ(tags.size(), 2); @@ -213,7 +213,7 @@ namespace UnitTest // Set the customized alias AZStd::string customizedAliasFilePath; - const char* assetsAlias = AZ::IO::FileIOBase::GetInstance()->GetAlias("@assets@"); + const char* assetsAlias = AZ::IO::FileIOBase::GetInstance()->GetAlias("@products@"); AzFramework::StringFunc::AssetDatabasePath::Join(assetsAlias, "foo", customizedAliasFilePath); AZ::IO::FileIOBase::GetInstance()->SetAlias("@customizedalias@", customizedAliasFilePath.c_str()); @@ -305,7 +305,7 @@ namespace UnitTest m_data->m_excludeFileQueryManager->ClearData(); EXPECT_TRUE(m_data->m_excludeFileQueryManager->Load(m_data->m_excludeFile)); - + AZStd::set outputTags = m_data->m_excludeFileQueryManager->GetTags(MatchingWildcardFile); EXPECT_EQ(outputTags.size(), 2); diff --git a/Code/Framework/AzFramework/Tests/GenAppDescriptors.cpp b/Code/Framework/AzFramework/Tests/GenAppDescriptors.cpp index 169834249f..665c06b571 100644 --- a/Code/Framework/AzFramework/Tests/GenAppDescriptors.cpp +++ b/Code/Framework/AzFramework/Tests/GenAppDescriptors.cpp @@ -6,81 +6,19 @@ * */ +#include #include #include #include -#include -#include +#include +#include namespace UnitTest { - using namespace AZ; - - class FileIOBaseRAII - { - public: - FileIOBaseRAII(AZ::IO::FileIOBase& fileIO) - : m_prevFileIO(AZ::IO::FileIOBase::GetInstance()) - { - AZ::IO::FileIOBase::SetInstance(&fileIO); - } - - ~FileIOBaseRAII() - { - AZ::IO::FileIOBase::SetInstance(m_prevFileIO); - } - private: - AZ::IO::FileIOBase* m_prevFileIO; - }; - class GenAppDescriptors : public AllocatorsTestFixture { public: - - void run() - { - struct Config - { - const char* platformName; - const char* configName; - const char* libSuffix; - }; - - ComponentApplication app; - - SerializeContext serializeContext; - AZ::ComponentApplication::Descriptor::Reflect(&serializeContext, &app); - AZ::Entity::Reflect(&serializeContext); - DynamicModuleDescriptor::Reflect(&serializeContext); - - AZ::Entity dummySystemEntity(AZ::SystemEntityId, "SystemEntity"); - - const Config config = {"Platform", "Config", "libSuffix"}; - - AZ::ComponentApplication::Descriptor descriptor; - - if (config.libSuffix && config.libSuffix[0]) - { - FakePopulateModules(descriptor, config.libSuffix); - } - - const AZStd::string filename = AZStd::string::format("LYConfig_%s%s.xml", config.platformName, config.configName); - - IO::FileIOStream stream(filename.c_str(), IO::OpenMode::ModeWrite); - ObjectStream* objStream = ObjectStream::Create(&stream, serializeContext, ObjectStream::ST_XML); - bool descWriteOk = objStream->WriteClass(&descriptor); - (void)descWriteOk; - AZ_Warning("ComponentApplication", descWriteOk, "Failed to write memory descriptor to application descriptor file %s!", filename.c_str()); - bool entityWriteOk = objStream->WriteClass(&dummySystemEntity); - (void)entityWriteOk; - AZ_Warning("ComponentApplication", entityWriteOk, "Failed to write system entity to application descriptor file %s!", filename.c_str()); - bool flushOk = objStream->Finalize(); - (void)flushOk; - AZ_Warning("ComponentApplication", flushOk, "Failed finalizing application descriptor file %s!", filename.c_str()); - - } - void FakePopulateModules(AZ::ComponentApplication::Descriptor& desc, const char* libSuffix) { static const char* modules[] = @@ -100,10 +38,44 @@ namespace UnitTest } }; - TEST_F(GenAppDescriptors, Test) + TEST_F(GenAppDescriptors, WriteDescriptor_ToXML_Succeeds) { - AZ::IO::LocalFileIO fileIO; - FileIOBaseRAII restoreFileIOScope(fileIO); - run(); + struct Config + { + const char* platformName; + const char* configName; + const char* libSuffix; + }; + + AzFramework::Application app; + + AZ::SerializeContext serializeContext; + AZ::ComponentApplication::Descriptor::Reflect(&serializeContext, &app); + AZ::Entity::Reflect(&serializeContext); + AZ::DynamicModuleDescriptor::Reflect(&serializeContext); + + AZ::Entity dummySystemEntity(AZ::SystemEntityId, "SystemEntity"); + + const Config config = {"Platform", "Config", "libSuffix"}; + + AZ::ComponentApplication::Descriptor descriptor; + + if (config.libSuffix && config.libSuffix[0]) + { + FakePopulateModules(descriptor, config.libSuffix); + } + + AZ::Test::ScopedAutoTempDirectory tempDirectory; + const auto filename = AZ::IO::Path(tempDirectory.GetDirectory()) / + AZStd::string::format("LYConfig_%s%s.xml", config.platformName, config.configName); + + AZ::IO::FileIOStream stream(filename.c_str(), AZ::IO::OpenMode::ModeWrite); + auto objStream = AZ::ObjectStream::Create(&stream, serializeContext, AZ::ObjectStream::ST_XML); + const bool descWriteOk = objStream->WriteClass(&descriptor); + EXPECT_TRUE(descWriteOk) << "Failed to write memory descriptor to application descriptor file " << filename.c_str() << "!"; + const bool entityWriteOk = objStream->WriteClass(&dummySystemEntity); + EXPECT_TRUE(entityWriteOk) << "Failed to write system entity to application descriptor file " << filename.c_str() << "!"; + const bool flushOk = objStream->Finalize(); + EXPECT_TRUE(flushOk) << "Failed finalizing application descriptor file " << filename.c_str() << "!"; } } diff --git a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp index 424132b624..462de43262 100644 --- a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp +++ b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp @@ -38,12 +38,12 @@ namespace AzGameFramework { // fall back to checking Project Cache Root. enginePakPath /= "engine.pak"; - enginePakOpened = m_archive->OpenPack("@projectproductassets@", enginePakPath.Native()); + enginePakOpened = m_archive->OpenPack("@products@", enginePakPath.Native()); } if (!enginePakOpened) { enginePakPath = AZ::IO::FixedMaxPath(AZ::Utils::GetExecutableDirectory()) / "engine.pak"; - m_archive->OpenPack("@projectproductassets@", enginePakPath.Native()); + m_archive->OpenPack("@products@", enginePakPath.Native()); } } diff --git a/Code/Framework/AzNetworking/AzNetworking/Utilities/EncryptionCommon.cpp b/Code/Framework/AzNetworking/AzNetworking/Utilities/EncryptionCommon.cpp index 3fdfa042a5..9f496c3e0c 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Utilities/EncryptionCommon.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/Utilities/EncryptionCommon.cpp @@ -107,7 +107,7 @@ namespace AzNetworking if (AZ::IO::FileIOBase::GetInstance() != nullptr) { char buffer[AZ_MAX_PATH_LEN]; - AZ::IO::FileIOBase::GetInstance()->ResolvePath("@assets@/", buffer, sizeof(buffer)); + AZ::IO::FileIOBase::GetInstance()->ResolvePath("@products@/", buffer, sizeof(buffer)); assetDir = AZStd::string(buffer); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/EditorAssetSystemAPI.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/EditorAssetSystemAPI.h index eab2d5e1a0..c18ddc2f67 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/EditorAssetSystemAPI.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/EditorAssetSystemAPI.h @@ -47,14 +47,6 @@ namespace AzToolsFramework //! Retrieve the absolute path for the Asset Database Location virtual bool GetAbsoluteAssetDatabaseLocation(AZStd::string& /*result*/) { return false; } - - //! Retrieve the absolute folder path to the current game's source assets (the ones that go into source control) - //! This may include the current mod path, if a mod is being edited by the editor - virtual const char* GetAbsoluteDevGameFolderPath() = 0; - - //! Retrieve the absolute folder path to the current developer root ('dev'), which contains source artifacts - //! and is generally checked into source control. - virtual const char* GetAbsoluteDevRootFolderPath() = 0; /// Convert a full source path like "c:\\dev\\gamename\\blah\\test.tga" into a relative product path. /// asset paths never mention their alias and are relative to the asset cache root diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetSystemComponent.cpp index cc3153ed8e..86b32d4379 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetSystemComponent.cpp @@ -354,26 +354,6 @@ namespace AzToolsFramework } } - const char* AssetSystemComponent::GetAbsoluteDevGameFolderPath() - { - AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); - if (fileIO) - { - return fileIO->GetAlias("@devassets@"); - } - return ""; - } - - const char* AssetSystemComponent::GetAbsoluteDevRootFolderPath() - { - AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); - if (fileIO) - { - return fileIO->GetAlias("@devroot@"); - } - return ""; - } - void AssetSystemComponent::OnSystemTick() { AssetSystemBus::ExecuteQueuedEvents(); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetSystemComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetSystemComponent.h index 4774b96be4..fcd697393c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetSystemComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetSystemComponent.h @@ -56,8 +56,6 @@ namespace AzToolsFramework ////////////////////////////////////////////////////////////////////////// // AzToolsFramework::AssetSystemRequestBus::Handler overrides bool GetAbsoluteAssetDatabaseLocation(AZStd::string& result) override; - const char* GetAbsoluteDevGameFolderPath() override; - const char* GetAbsoluteDevRootFolderPath() override; bool GetRelativeProductPathFromFullSourceOrProductPath(const AZStd::string& fullPath, AZStd::string& outputPath) override; bool GenerateRelativeSourcePath( const AZStd::string& sourcePath, AZStd::string& outputPath, AZStd::string& watchFolder) override; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorWidget.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorWidget.cpp index e09dd183f8..8856989911 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorWidget.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetEditor/AssetEditorWidget.cpp @@ -137,7 +137,7 @@ namespace AzToolsFramework AssetEditorWidgetUserSettings::AssetEditorWidgetUserSettings() { char assetRoot[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath("@devassets@", assetRoot, AZ_MAX_PATH_LEN); + AZ::IO::FileIOBase::GetInstance()->ResolvePath("@projectroot@", assetRoot, AZ_MAX_PATH_LEN); m_lastSavePath = assetRoot; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Debug/TraceContext.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Debug/TraceContext.h index 988963eaca..3ba826804d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Debug/TraceContext.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Debug/TraceContext.h @@ -39,7 +39,7 @@ namespace AzToolsFramework // the TraceContextLogFormatter. // // Usage example: - // const char* gameFolder = m_context.pRC->GetSystemEnvironment()->pFileIO->GetAlias("@devassets@"); + // const char* gameFolder = m_context.pRC->GetSystemEnvironment()->pFileIO->GetAlias("@projectroot@"); // AZ_TraceContext("Game folder", gameFolder); // // for (int i=0; iSetAlias("@log@", logDirectory.c_str()); - fileIO->CreatePath("@root@"); + fileIO->CreatePath("@products@"); fileIO->CreatePath("@user@"); fileIO->CreatePath("@log@"); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceRequestComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceRequestComponent.cpp index 36f647e4c2..99d0768cf6 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceRequestComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceRequestComponent.cpp @@ -8,6 +8,7 @@ #include +#include #include #include #include @@ -78,13 +79,9 @@ namespace AzToolsFramework AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(entitiesAndDescendants, &AzToolsFramework::ToolsApplicationRequestBus::Events::GatherEntitiesAndAllDescendents, AzToolsFramework::EntityIdList{ entityId }); - // Retrieve the game folder so we can use that as a root with the passed in relative path - const char* gameFolder = nullptr; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(gameFolder, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetAbsoluteDevGameFolderPath); - // Join our relative path with the game folder to get a full path to the desired asset - AZStd::string assetFullPath; - AzFramework::StringFunc::Path::Join(gameFolder, assetPath, assetFullPath); + AZ::IO::FixedMaxPath assetFullPath = AZ::Utils::GetProjectPath(); + assetFullPath /= assetPath; // Call SliceUtilities::MakeNewSlice with all user input prompts disabled bool success = AzToolsFramework::SliceUtilities::MakeNewSlice(entitiesAndDescendants, diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceTransaction.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceTransaction.cpp index d8b5fe0a15..9d2c58a717 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceTransaction.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceTransaction.cpp @@ -718,7 +718,7 @@ namespace AzToolsFramework if (!fullPathFound) { - assetFullPath = AZStd::string::format("@devassets@/%s", sliceAssetPath.c_str()); + assetFullPath = AZStd::string::format("@projectroot@/%s", sliceAssetPath.c_str()); } return Commit(assetFullPath.c_str(), preSaveCallback, postSaveCallback, sliceCommitFlags); @@ -1020,13 +1020,13 @@ namespace AzToolsFramework AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); AZ_Assert(fileIO, "File IO is not initialized."); - AZStd::string devAssetPath = fileIO->GetAlias("@devassets@"); + AZStd::string devAssetPath = fileIO->GetAlias("@projectroot@"); AZStd::string userPath = fileIO->GetAlias("@user@"); AZStd::string tempPath = fullPath; EBUS_EVENT(AzFramework::ApplicationRequests::Bus, NormalizePath, devAssetPath); EBUS_EVENT(AzFramework::ApplicationRequests::Bus, NormalizePath, userPath); EBUS_EVENT(AzFramework::ApplicationRequests::Bus, NormalizePath, tempPath); - AzFramework::StringFunc::Replace(tempPath, "@devassets@", devAssetPath.c_str()); + AzFramework::StringFunc::Replace(tempPath, "@projectroot@", devAssetPath.c_str()); AzFramework::StringFunc::Replace(tempPath, devAssetPath.c_str(), userPath.c_str()); tempPath.append(".slicetemp"); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorLayerComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorLayerComponent.cpp index f58f273f11..01b1213473 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorLayerComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/EditorLayerComponent.cpp @@ -378,11 +378,11 @@ namespace AzToolsFramework // If this layer is being loaded, it won't have a level save dependency yet, so clear that flag. m_mustSaveLevelWhenLayerSaves = false; QString fullPathName = levelPakFile; - if (fullPathName.contains("@devassets@")) + if (fullPathName.contains("@projectroot@")) { AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); // Resolving the path through resolvepath would normalize and lowcase it, and in this case, we don't want that. - fullPathName.replace("@devassets@", fileIO->GetAlias("@devassets@")); + fullPathName.replace("@projectroot@", fileIO->GetAlias("@projectroot@")); } QFileInfo fileNameInfo(fullPathName); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp index 62842e18d5..07dcd2ab20 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp @@ -315,7 +315,7 @@ namespace AzToolsFramework // temporarily null after QFileDialogs close, which we need in order to // be able to parent our message dialogs properly QWidget* activeWindow = QApplication::activeWindow(); - const AZStd::string prefabFilesPath = "@devassets@/Prefabs"; + const AZStd::string prefabFilesPath = "@projectroot@/Prefabs"; // Remove Level entity if it's part of the list diff --git a/Code/Framework/AzToolsFramework/Tests/ArchiveTests.cpp b/Code/Framework/AzToolsFramework/Tests/ArchiveTests.cpp index 66520c804c..395e4c9049 100644 --- a/Code/Framework/AzToolsFramework/Tests/ArchiveTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/ArchiveTests.cpp @@ -131,13 +131,13 @@ namespace UnitTest m_app.reset(aznew ToolsTestApplication("ArchiveComponentTest")); m_app->Start(AzFramework::Application::Descriptor()); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); if (auto fileIoBase = AZ::IO::FileIOBase::GetInstance(); fileIoBase != nullptr) { - fileIoBase->SetAlias("@assets@", m_tempDir.GetDirectory()); + fileIoBase->SetAlias("@products@", m_tempDir.GetDirectory()); } } diff --git a/Code/Framework/AzToolsFramework/Tests/AssetSeedManager.cpp b/Code/Framework/AzToolsFramework/Tests/AssetSeedManager.cpp index 24488f3ed3..827737f561 100644 --- a/Code/Framework/AzToolsFramework/Tests/AssetSeedManager.cpp +++ b/Code/Framework/AzToolsFramework/Tests/AssetSeedManager.cpp @@ -37,10 +37,10 @@ namespace // anonymous bool Search(const AzToolsFramework::AssetFileInfoList& assetList, const AZ::Data::AssetId& assetId) { - return AZStd::find_if(assetList.m_fileInfoList.begin(), assetList.m_fileInfoList.end(), - [&](AzToolsFramework::AssetFileInfo fileInfo) - { - return fileInfo.m_assetId == assetId; + return AZStd::find_if(assetList.m_fileInfoList.begin(), assetList.m_fileInfoList.end(), + [&](AzToolsFramework::AssetFileInfo fileInfo) + { + return fileInfo.m_assetId == assetId; }); } } @@ -74,11 +74,11 @@ namespace UnitTest m_application->Start(AzFramework::Application::Descriptor()); - // By default @assets@ is setup to include the platform at the end. But this test is going to + // By default @products@ is setup to include the platform at the end. But this test is going to // loop over platforms and it will be included as part of the relative path of the file. // So the asset folder for these tests have to point to the cache project root folder, which // doesn't include the platform. - AZ::IO::FileIOBase::GetInstance()->SetAlias("@assets@", cacheProjectRootFolder.c_str()); + AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", cacheProjectRootFolder.c_str()); for (int idx = 0; idx < s_totalAssets; idx++) { @@ -158,17 +158,17 @@ namespace UnitTest m_assetRegistry->RegisterAssetDependency(assets[5], AZ::Data::ProductDependency(assets[6], 0)); m_assetRegistry->RegisterAssetDependency(assets[6], AZ::Data::ProductDependency(assets[7], 0)); - // asset8 -> asset6 + // asset8 -> asset6 m_assetRegistry->RegisterAssetDependency(assets[8], AZ::Data::ProductDependency(assets[6], 0)); - // asset10 -> asset11 + // asset10 -> asset11 m_assetRegistry->RegisterAssetDependency(assets[10], AZ::Data::ProductDependency(assets[11], 0)); - // asset11 -> asset10 + // asset11 -> asset10 m_assetRegistry->RegisterAssetDependency(assets[11], AZ::Data::ProductDependency(assets[10], 0)); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); @@ -203,10 +203,6 @@ namespace UnitTest const AZStd::string engroot = AZ::Test::GetEngineRootPath(); AZ::IO::FileIOBase::GetInstance()->SetAlias("@engroot@", engroot.c_str()); - - AZ::IO::Path assetRoot(AZ::Utils::GetProjectPath()); - assetRoot /= "Cache"; - AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", assetRoot.c_str()); } void TearDown() override @@ -219,7 +215,7 @@ namespace UnitTest delete m_application; } - AZ::Data::AssetInfo GetAssetInfoById(const AZ::Data::AssetId& id) override + AZ::Data::AssetInfo GetAssetInfoById(const AZ::Data::AssetId& id) override { auto foundIter = m_assetRegistry->m_assetIdToInfo.find(id); if (foundIter != m_assetRegistry->m_assetIdToInfo.end()) @@ -540,7 +536,7 @@ namespace UnitTest EXPECT_TRUE(Search(assetList, assets[7])); EXPECT_TRUE(Search(assetList, assets[8])); - // Removing the android flag from the asset should still produce the same result + // Removing the android flag from the asset should still produce the same result m_assetSeedManager->RemoveSeedAsset(assets[8], AzFramework::PlatformFlags::Platform_ANDROID); assetList = m_assetSeedManager->GetDependencyList(AzFramework::PlatformId::PC); @@ -564,7 +560,7 @@ namespace UnitTest EXPECT_TRUE(Search(assetList, assets[3])); EXPECT_TRUE(Search(assetList, assets[4])); - // Adding the android flag again to the asset + // Adding the android flag again to the asset m_assetSeedManager->AddSeedAsset(assets[8], AzFramework::PlatformFlags::Platform_ANDROID); assetList = m_assetSeedManager->GetDependencyList(AzFramework::PlatformId::ANDROID_ID); @@ -624,7 +620,7 @@ namespace UnitTest EXPECT_EQ(assetList1.m_fileInfoList[0].m_assetId, assetList2.m_fileInfoList[0].m_assetId); EXPECT_GE(assetList2.m_fileInfoList[0].m_modificationTime, assetList1.m_fileInfoList[0].m_modificationTime); // file mod time should change - + // file hash should not change for (int idx = 0; idx < 5; idx++) { @@ -680,7 +676,7 @@ namespace UnitTest m_assetSeedManager->AddSeedAsset(assets[validFileIndex], AzFramework::PlatformFlags::Platform_PC, m_assetsPath[invalidFileIndex]); const AzFramework::AssetSeedList& oldSeedList = m_assetSeedManager->GetAssetSeedList(); - + for (const auto& seedInfo : oldSeedList) { if (seedInfo.m_assetId == assets[validFileIndex]) diff --git a/Code/Framework/AzToolsFramework/Tests/AssetSystemMocks.h b/Code/Framework/AzToolsFramework/Tests/AssetSystemMocks.h index 2678c2f57c..ba3e38ba8f 100644 --- a/Code/Framework/AzToolsFramework/Tests/AssetSystemMocks.h +++ b/Code/Framework/AzToolsFramework/Tests/AssetSystemMocks.h @@ -18,8 +18,6 @@ namespace UnitTests { public: MOCK_METHOD1(GetAbsoluteAssetDatabaseLocation, bool(AZStd::string&)); - MOCK_METHOD0(GetAbsoluteDevGameFolderPath, const char* ()); - MOCK_METHOD0(GetAbsoluteDevRootFolderPath, const char* ()); MOCK_METHOD2(GetRelativeProductPathFromFullSourceOrProductPath, bool(const AZStd::string& fullPath, AZStd::string& relativeProductPath)); MOCK_METHOD3(GenerateRelativeSourcePath, bool(const AZStd::string& sourcePath, AZStd::string& relativePath, AZStd::string& watchFolder)); diff --git a/Code/Framework/AzToolsFramework/Tests/EntityTestbed.h b/Code/Framework/AzToolsFramework/Tests/EntityTestbed.h index 2128b3676a..1bf51045c0 100644 --- a/Code/Framework/AzToolsFramework/Tests/EntityTestbed.h +++ b/Code/Framework/AzToolsFramework/Tests/EntityTestbed.h @@ -181,8 +181,8 @@ namespace UnitTest const char* dir = m_componentApplication->GetExecutableFolder(); - m_localFileIO.SetAlias("@assets@", dir); - m_localFileIO.SetAlias("@devassets@", dir); + m_localFileIO.SetAlias("@products@", dir); + m_localFileIO.SetAlias("@projectroot@", dir); } void Destroy() diff --git a/Code/Framework/AzToolsFramework/Tests/PlatformAddressedAssetCatalogTests.cpp b/Code/Framework/AzToolsFramework/Tests/PlatformAddressedAssetCatalogTests.cpp index 67d40be376..9c226cbb1b 100644 --- a/Code/Framework/AzToolsFramework/Tests/PlatformAddressedAssetCatalogTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/PlatformAddressedAssetCatalogTests.cpp @@ -22,7 +22,7 @@ #include #include -namespace +namespace { static const int s_totalAssets = 12; } @@ -53,15 +53,15 @@ namespace UnitTest m_application->Start(AzFramework::Application::Descriptor()); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); - // By default @assets@ is setup to include the platform at the end. But this test is going to + // By default @products@ is setup to include the platform at the end. But this test is going to // loop over all platforms and it will be included as part of the relative path of the file. // So the asset folder for these tests have to point to the cache project root folder, which // doesn't include the platform. - AZ::IO::FileIOBase::GetInstance()->SetAlias("@assets@", cacheProjectRootFolder.c_str()); + AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", cacheProjectRootFolder.c_str()); for (int platformNum = AzFramework::PlatformId::PC; platformNum < AzFramework::PlatformId::NumPlatformIds; ++platformNum) { diff --git a/Code/Framework/AzToolsFramework/Tests/SliceStabilityTests/SliceStabilityTestFramework.h b/Code/Framework/AzToolsFramework/Tests/SliceStabilityTests/SliceStabilityTestFramework.h index 93e86374db..01b40fbb16 100644 --- a/Code/Framework/AzToolsFramework/Tests/SliceStabilityTests/SliceStabilityTestFramework.h +++ b/Code/Framework/AzToolsFramework/Tests/SliceStabilityTests/SliceStabilityTestFramework.h @@ -142,8 +142,6 @@ namespace UnitTest /* * AssetSystemRequestBus */ - const char* GetAbsoluteDevGameFolderPath() override { return ""; } - const char* GetAbsoluteDevRootFolderPath() override { return ""; } bool GetRelativeProductPathFromFullSourceOrProductPath([[maybe_unused]] const AZStd::string& fullPath, [[maybe_unused]] AZStd::string& relativeProductPath) override { return false; } bool GenerateRelativeSourcePath( [[maybe_unused]] const AZStd::string& sourcePath, [[maybe_unused]] AZStd::string& relativePath, diff --git a/Code/Legacy/CryCommon/CryPath.h b/Code/Legacy/CryCommon/CryPath.h index 197c9b2d56..51b379ac51 100644 --- a/Code/Legacy/CryCommon/CryPath.h +++ b/Code/Legacy/CryCommon/CryPath.h @@ -520,14 +520,14 @@ namespace PathUtil unsigned int index = 0; if (relativePath.length() && relativePath[index] == '@') // already aliased { - if (AZ::StringFunc::Equal(relativePath.c_str(), "@assets@/", false, 9)) + if (AZ::StringFunc::Equal(relativePath.c_str(), "@products@/", false, 9)) { return relativePath.substr(9); // assets is assumed. } return relativePath; } - const char* rootValue = gEnv->pFileIO->GetAlias("@root@"); + const char* rootValue = gEnv->pFileIO->GetAlias("@products@"); if (rootValue) { stack_string rootPath(ToUnixPath(rootValue)); @@ -538,7 +538,7 @@ namespace PathUtil ) { stack_string chopped_string = relativePath.substr(rootPath.size()); - stack_string rooted = stack_string("@root@") + chopped_string; + stack_string rooted = stack_string("@products@") + chopped_string; return rooted; } } diff --git a/Code/Legacy/CrySystem/ConsoleBatchFile.cpp b/Code/Legacy/CrySystem/ConsoleBatchFile.cpp index bdc8d6de7d..5b96b943a7 100644 --- a/Code/Legacy/CrySystem/ConsoleBatchFile.cpp +++ b/Code/Legacy/CrySystem/ConsoleBatchFile.cpp @@ -59,10 +59,10 @@ bool CConsoleBatchFile::ExecuteConfigFile(const char* sFilename) AZStd::string filename; - if (sFilename[0] != '@') // console config files are actually by default in @root@ instead of @assets@ + if (sFilename[0] != '@') // console config files are actually by default in @products@ instead of @products@ { // However, if we've passed in a relative or absolute path that matches an existing file name, - // don't change it. Only change it to "@root@/filename" and strip off any relative paths + // don't change it. Only change it to "@products@/filename" and strip off any relative paths // if the given pattern *didn't* match a file. if (AZ::IO::FileIOBase::GetDirectInstance()->Exists(sFilename)) { @@ -70,7 +70,7 @@ bool CConsoleBatchFile::ExecuteConfigFile(const char* sFilename) } else { - filename = PathUtil::Make("@root@", PathUtil::GetFile(sFilename)); + filename = PathUtil::Make("@products@", PathUtil::GetFile(sFilename)); } } else diff --git a/Code/Legacy/CrySystem/DebugCallStack.cpp b/Code/Legacy/CrySystem/DebugCallStack.cpp index bea6c8c035..8018e46d69 100644 --- a/Code/Legacy/CrySystem/DebugCallStack.cpp +++ b/Code/Legacy/CrySystem/DebugCallStack.cpp @@ -372,7 +372,7 @@ void DebugCallStack::LogExceptionInfo(EXCEPTION_POINTERS* pex) const char* logAlias = gEnv->pFileIO->GetAlias("@log@"); if (!logAlias) { - logAlias = gEnv->pFileIO->GetAlias("@root@"); + logAlias = gEnv->pFileIO->GetAlias("@products@"); } if (logAlias) { diff --git a/Code/Legacy/CrySystem/LevelSystem/LevelSystem.cpp b/Code/Legacy/CrySystem/LevelSystem/LevelSystem.cpp index 2e61760d8c..49af5080ec 100644 --- a/Code/Legacy/CrySystem/LevelSystem/LevelSystem.cpp +++ b/Code/Legacy/CrySystem/LevelSystem/LevelSystem.cpp @@ -306,7 +306,7 @@ void CLevelSystem::ScanFolder(const char* subfolder, bool modFolder) } AZStd::string levelContainerPakPath; - AZ::StringFunc::Path::Join("@assets@", m_levelsFolder.c_str(), levelContainerPakPath); + AZ::StringFunc::Path::Join("@products@", m_levelsFolder.c_str(), levelContainerPakPath); if (subfolder && subfolder[0]) { AZ::StringFunc::Path::Join(levelContainerPakPath.c_str(), subfolder, levelContainerPakPath); diff --git a/Code/Legacy/CrySystem/SystemCFG.cpp b/Code/Legacy/CrySystem/SystemCFG.cpp index c97345a518..7a643f2069 100644 --- a/Code/Legacy/CrySystem/SystemCFG.cpp +++ b/Code/Legacy/CrySystem/SystemCFG.cpp @@ -292,10 +292,10 @@ static bool ParseSystemConfig(const AZStd::string& strSysConfigFilePath, ILoadCo // to either root or assets/config. this is done so that code can just request a simple file name and get its data if ( !(file.Open(filename.c_str(), "rb")) && - !(file.Open((AZStd::string("@root@/") + filename).c_str(), "rb")) && - !(file.Open((AZStd::string("@assets@/") + filename).c_str(), "rb")) && - !(file.Open((AZStd::string("@assets@/config/") + filename).c_str(), "rb")) && - !(file.Open((AZStd::string("@assets@/config/spec/") + filename).c_str(), "rb")) + !(file.Open((AZStd::string("@products@/") + filename).c_str(), "rb")) && + !(file.Open((AZStd::string("@products@/") + filename).c_str(), "rb")) && + !(file.Open((AZStd::string("@products@/config/") + filename).c_str(), "rb")) && + !(file.Open((AZStd::string("@products@/config/spec/") + filename).c_str(), "rb")) ) { if (warnIfMissing) @@ -414,7 +414,7 @@ static bool ParseSystemConfig(const AZStd::string& strSysConfigFilePath, ILoadCo // replace '\\\\' with '\\' and '\\\"' with '\"' AZ::StringFunc::Replace(strValue, "\\\\", "\\"); AZ::StringFunc::Replace(strValue, "\\\"", "\""); - + pSink->OnLoadConfigurationEntry(strKey.c_str(), strValue.c_str(), strGroup.c_str()); } } diff --git a/Code/Legacy/CrySystem/SystemInit.cpp b/Code/Legacy/CrySystem/SystemInit.cpp index 3187095094..6de10f3855 100644 --- a/Code/Legacy/CrySystem/SystemInit.cpp +++ b/Code/Legacy/CrySystem/SystemInit.cpp @@ -796,7 +796,7 @@ void CSystem::OpenBasicPaks() bBasicPaksLoaded = true; // open pak files - constexpr AZStd::string_view paksFolder = "@assets@/*.pak"; // (@assets@ assumed) + constexpr AZStd::string_view paksFolder = "@products@/*.pak"; // (@products@ assumed) m_env.pCryPak->OpenPacks(paksFolder); InlineInitializationProcessing("CSystem::OpenBasicPaks OpenPacks( paksFolder.c_str() )"); @@ -805,7 +805,7 @@ void CSystem::OpenBasicPaks() // Open engine packs ////////////////////////////////////////////////////////////////////////// - const char* const assetsDir = "@assets@"; + const char* const assetsDir = "@products@"; // After game paks to have same search order as with files on disk m_env.pCryPak->OpenPack(assetsDir, "engine.pak"); @@ -874,7 +874,7 @@ void CSystem::OpenLanguageAudioPak([[maybe_unused]] const char* sLanguage) if (!AZ::StringFunc::Equal(sLocalizationFolder, "Languages", false)) { - sLocalizationFolder = "@assets@"; + sLocalizationFolder = "@products@"; } // load localized pak with crc32 filenames on consoles to save memory. @@ -1260,9 +1260,6 @@ AZ_POP_DISABLE_WARNING InlineInitializationProcessing("CSystem::Init Create console"); - // Need to load the engine.pak that includes the config files needed during initialization - m_env.pCryPak->OpenPack("@assets@", "engine.pak"); - InitFileSystem_LoadEngineFolders(startupParams); #if !defined(RELEASE) || defined(RELEASE_LOGGING) diff --git a/Code/Tools/AWSNativeSDKInit/source/Platform/Android/InitializeCerts_Android.cpp b/Code/Tools/AWSNativeSDKInit/source/Platform/Android/InitializeCerts_Android.cpp index e0a6725ed4..24366498a5 100644 --- a/Code/Tools/AWSNativeSDKInit/source/Platform/Android/InitializeCerts_Android.cpp +++ b/Code/Tools/AWSNativeSDKInit/source/Platform/Android/InitializeCerts_Android.cpp @@ -27,7 +27,7 @@ namespace AWSNativeSDKInit void CopyCaCertBundle() { AZStd::vector contents; - AZStd::string certificatePath = "@assets@/certificates/aws/cacert.pem"; + AZStd::string certificatePath = "@products@/certificates/aws/cacert.pem"; AZStd::string publicStoragePath = AZ::Android::Utils::GetAppPublicStoragePath(); publicStoragePath.append("/certificates/aws/cacert.pem"); diff --git a/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.cpp b/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.cpp index 42a43ef84e..78244ab02c 100644 --- a/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.cpp +++ b/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.cpp @@ -683,31 +683,26 @@ void AssetBuilderComponent::ProcessJob(const AssetBuilderSDK::ProcessJobFunction AZ_Assert(settingsRegistry != nullptr, "SettingsRegistry must be ready for use in the AssetBuilder."); // The root path is the cache plus the platform name. - AZ::IO::FixedMaxPath newRoot(m_gameCache); + AZ::IO::FixedMaxPath newProjectCache(m_gameCache); // Check if the platform identifier is a valid "asset platform" // If so, use it, other wise use the OS default platform as a fail safe // This is to make sure the "debug platform" isn't added as a path segment - // the Cache Root folder + // the Cache ProjectCache folder if (AzFramework::PlatformHelper::GetPlatformIdFromName(request.m_platformInfo.m_identifier) != AzFramework::PlatformId::Invalid) { - newRoot /= request.m_platformInfo.m_identifier; + newProjectCache /= request.m_platformInfo.m_identifier; } else { - newRoot /= AzFramework::OSPlatformToDefaultAssetPlatform(AZ_TRAIT_OS_PLATFORM_CODENAME); + newProjectCache /= AzFramework::OSPlatformToDefaultAssetPlatform(AZ_TRAIT_OS_PLATFORM_CODENAME); } - // The asset path is root and the lower case game name. - AZ::IO::FixedMaxPath newAssets = newRoot; - // Now set the paths and run the job. { // Save out the prior paths. - ScopedAliasSetter assetAliasScope(*ioBase, "@assets@", newAssets.c_str()); - ScopedAliasSetter rootAliasScope(*ioBase, "@root@", newRoot.c_str()); - ScopedAliasSetter projectplatformCacheAliasScope(*ioBase, "@projectplatformcache@", newRoot.c_str()); + ScopedAliasSetter projectPlatformCacheAliasScope(*ioBase, "@products@", newProjectCache.c_str()); ScopedSettingsRegistrySetter cacheRootFolderScope(*settingsRegistry, - AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder, newRoot.Native()); + AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder, newProjectCache.Native()); // Invoke the Process Job function job(request, outResponse); diff --git a/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.cpp b/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.cpp index 6eee3d6f2b..d7cdd30be8 100644 --- a/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.cpp +++ b/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.cpp @@ -27,7 +27,7 @@ namespace AssetProcessor , m_registryBuiltOnce(false) , m_registriesMutex(QMutex::Recursive) { - + for (const AssetBuilderSDK::PlatformInfo& info : m_platformConfig->GetEnabledPlatforms()) { m_platforms.push_back(QString::fromUtf8(info.m_identifier.c_str())); @@ -38,17 +38,9 @@ namespace AssetProcessor // save 30mb for this. Really large projects do get this big (and bigger) // if you don't do this, things get fragmented very fast. - m_saveBuffer.reserve(1024 * 1024 * 30); - - m_absoluteDevFolderPath[0] = 0; - m_absoluteDevGameFolderPath[0] = 0; + m_saveBuffer.reserve(1024 * 1024 * 30); - AZStd::string engineRoot; - AzFramework::ApplicationRequests::Bus::BroadcastResult(engineRoot, &AzFramework::ApplicationRequests::GetEngineRoot); - azstrcpy(m_absoluteDevFolderPath, AZ_MAX_PATH_LEN, engineRoot.c_str()); - - AZStd::string gameFolderPath{AssetUtilities::ComputeProjectPath().toUtf8().constData()}; - azstrcpy(m_absoluteDevGameFolderPath, AZ_MAX_PATH_LEN, gameFolderPath.c_str()); + AssetUtilities::ComputeProjectPath(); AssetUtilities::ComputeProjectCacheRoot(m_cacheRootDir); @@ -359,7 +351,7 @@ namespace AssetProcessor [[maybe_unused]] bool makeDirResult = AZ::IO::SystemFile::CreateDir(absPath.toUtf8().constData()); AZ_Warning(AssetProcessor::ConsoleChannel, makeDirResult, "Failed create folder %s", platformCacheDir.toUtf8().constData()); } - + // if we succeeded in doing this, then use "rename" to move the file over the previous copy. bool moved = AssetUtilities::MoveFileWithTimeout(tempRegistryFile, actualRegistryFile, 3); allCatalogsSaved = allCatalogsSaved && moved; @@ -382,7 +374,7 @@ namespace AssetProcessor } } } - + { // scoped to minimize the duration of this mutex lock QMutexLocker locker(&m_savingRegistryMutex); @@ -605,7 +597,7 @@ namespace AssetProcessor AZStd::string nameForMap(relativeFilePath.toUtf8().constData()); AZStd::to_lower(nameForMap.begin(), nameForMap.end()); - + m_sourceNameToSourceUUIDMap.insert({ nameForMap, sourceUuid }); } @@ -627,16 +619,6 @@ namespace AssetProcessor ////////////////////////////////////////////////////////////////////////// - const char* AssetCatalog::GetAbsoluteDevGameFolderPath() - { - return m_absoluteDevGameFolderPath; - } - - const char* AssetCatalog::GetAbsoluteDevRootFolderPath() - { - return m_absoluteDevFolderPath; - } - bool AssetCatalog::GetRelativeProductPathFromFullSourceOrProductPath(const AZStd::string& fullSourceOrProductPath, AZStd::string& relativeProductPath) { ProcessGetRelativeProductPathFromFullSourceOrProductPathRequest(fullSourceOrProductPath, relativeProductPath); @@ -976,7 +958,7 @@ namespace AssetProcessor // regardless of which way we come into this function we must always use ConvertToRelativePath // to convert from whatever the input format is to a database path (which may include output prefix) - QString databaseName; + QString databaseName; QString scanFolder; if (!AzFramework::StringFunc::Path::IsRelative(sourcePath)) { @@ -1163,7 +1145,7 @@ namespace AssetProcessor AZStd::string AssetCatalog::GetAssetPathById(const AZ::Data::AssetId& id) { return GetAssetInfoById(id).m_relativePath; - + } AZ::Data::AssetId AssetCatalog::GetAssetIdByPath(const char* path, const AZ::Data::AssetType& typeToRegister, bool autoRegisterIfNotFound) @@ -1175,7 +1157,7 @@ namespace AssetProcessor AZStd::string relProductPath; GetRelativeProductPathFromFullSourceOrProductPath(path, relProductPath); QString tempPlatformName = GetDefaultAssetPlatform(); - + AZ::Data::AssetId assetId; { QMutexLocker locker(&m_registriesMutex); @@ -1344,7 +1326,7 @@ namespace AssetProcessor //remove aliases if present normalisedAssetPath = AssetUtilities::NormalizeAndRemoveAlias(normalisedAssetPath); - if (!normalisedAssetPath.isEmpty()) // this happens if it comes in as just for example "@assets@/" + if (!normalisedAssetPath.isEmpty()) // this happens if it comes in as just for example "@products@/" { AZStd::lock_guard lock(m_databaseMutex); @@ -1439,7 +1421,7 @@ namespace AssetProcessor relativePath = entry.m_sourceName; watchFolder = scanEntry.m_scanFolder; - + return true; } @@ -1489,7 +1471,7 @@ namespace AssetProcessor { return foundIter->second; } - + // we did not find it - try the backup mapping! AssetId legacyMapping = registryToUse.GetAssetIdByLegacyAssetId(assetId); if (legacyMapping.IsValid()) @@ -1533,7 +1515,7 @@ namespace AssetProcessor return !assetInfo.m_relativePath.empty(); } - + // Asset isn't in the DB or in the APM queue, we don't know what this asset ID is return false; } @@ -1588,7 +1570,7 @@ namespace AssetProcessor AZStd::string sourceFileFullPath; AzFramework::StringFunc::Path::Join(watchFolder.c_str(), assetInfo.m_relativePath.c_str(), sourceFileFullPath); assetInfo.m_sizeBytes = AZ::IO::SystemFile::Length(sourceFileFullPath.c_str()); - + assetInfo.m_assetType = AZ::Uuid::CreateNull(); // most source files don't have a type! // Go through the list of source assets and see if this asset's file path matches any of the filters diff --git a/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.h b/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.h index 84e96bcf3e..e876e259fb 100644 --- a/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.h +++ b/Code/Tools/AssetProcessor/native/AssetManager/AssetCatalog.h @@ -88,8 +88,6 @@ namespace AssetProcessor ////////////////////////////////////////////////////////////////////////// // AzToolsFramework::AssetSystem::AssetSystemRequestBus::Handler overrides - const char* GetAbsoluteDevGameFolderPath() override; - const char* GetAbsoluteDevRootFolderPath() override; bool GetRelativeProductPathFromFullSourceOrProductPath(const AZStd::string& fullPath, AZStd::string& relativeProductPath) override; //! Given a partial or full source file path, respond with its relative path and the watch folder it is relative to. @@ -215,8 +213,6 @@ namespace AssetProcessor AZStd::vector m_saveBuffer; // so that we don't realloc all the time - char m_absoluteDevFolderPath[AZ_MAX_PATH_LEN]; - char m_absoluteDevGameFolderPath[AZ_MAX_PATH_LEN]; QDir m_cacheRootDir; }; } diff --git a/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp b/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp index 3a7bc6ef3e..4cd4489a4c 100644 --- a/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp +++ b/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp @@ -56,15 +56,8 @@ namespace AssetProcessor // cache this up front. Note that it can fail here, and will retry later. InitializeCacheRoot(); - m_absoluteDevFolderPath[0] = 0; - m_absoluteDevGameFolderPath[0] = 0; - QDir assetRoot; - if (AssetUtilities::ComputeAssetRoot(assetRoot)) - { - azstrcpy(m_absoluteDevFolderPath, AZ_MAX_PATH_LEN, assetRoot.absolutePath().toUtf8().constData()); - azstrcpy(m_absoluteDevGameFolderPath, AZ_MAX_PATH_LEN, AssetUtilities::ComputeProjectPath().toUtf8().constData()); - } + AssetUtilities::ComputeAssetRoot(assetRoot); using namespace AZStd::placeholders; diff --git a/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.h b/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.h index 376af5d773..891e091f91 100644 --- a/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.h +++ b/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.h @@ -440,8 +440,6 @@ namespace AssetProcessor AZStd::mutex m_sourceUUIDToSourceInfoMapMutex; QString m_normalizedCacheRootPath; - char m_absoluteDevFolderPath[AZ_MAX_PATH_LEN]; - char m_absoluteDevGameFolderPath[AZ_MAX_PATH_LEN]; QDir m_cacheRootDir; bool m_isCurrentlyScanning = false; bool m_quitRequested = false; diff --git a/Code/Tools/AssetProcessor/native/FileServer/fileServer.cpp b/Code/Tools/AssetProcessor/native/FileServer/fileServer.cpp index 30d8e5fada..c35f3a4b0f 100644 --- a/Code/Tools/AssetProcessor/native/FileServer/fileServer.cpp +++ b/Code/Tools/AssetProcessor/native/FileServer/fileServer.cpp @@ -95,7 +95,7 @@ void FileServer::ConnectionAdded(unsigned int connId, Connection* connection) Q_UNUSED(connection); // Connection has not completed negotiation yet, register to be notified - // when we know what platform is connected and map the @assets@ alias then + // when we know what platform is connected and map the @products@ alias then connect(connection, &Connection::AssetPlatformChanged, this, [this, connection]() { auto fileIO = m_fileIOs[connection->ConnectionId()]; @@ -114,8 +114,7 @@ void FileServer::ConnectionAdded(unsigned int connId, Connection* connection) projectCacheRoot = QDir(projectCacheRoot.absoluteFilePath(assetPlatform)); } const char* projectCachePath = projectCacheRoot.absolutePath().toUtf8().data(); - fileIO->SetAlias("@assets@", projectCachePath); - fileIO->SetAlias("@root@", projectCachePath); + fileIO->SetAlias("@products@", projectCachePath); if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) { @@ -955,10 +954,10 @@ void FileServer::ProcessFileTreeRequest(unsigned int connId, unsigned int, unsig FileTreeResponse::FolderList folders; AZStd::vector untestedFolders; - if (fileIO->IsDirectory("@assets@")) + if (fileIO->IsDirectory("@products@")) { - folders.push_back("@assets@"); - untestedFolders.push_back("@assets@"); + folders.push_back("@products@"); + untestedFolders.push_back("@products@"); } if (fileIO->IsDirectory("@usercache@")) { @@ -975,11 +974,6 @@ void FileServer::ProcessFileTreeRequest(unsigned int connId, unsigned int, unsig folders.push_back("@log@"); untestedFolders.push_back("@log@"); } - if (fileIO->IsDirectory("@root@")) - { - folders.push_back("@root@"); - untestedFolders.push_back("@root@"); - } AZ::IO::Result res = ResultCode::Success; diff --git a/Code/Tools/AssetProcessor/native/tests/AssetCatalog/AssetCatalogUnitTests.cpp b/Code/Tools/AssetProcessor/native/tests/AssetCatalog/AssetCatalogUnitTests.cpp index 5d2d0e77d3..2a1c4e4755 100644 --- a/Code/Tools/AssetProcessor/native/tests/AssetCatalog/AssetCatalogUnitTests.cpp +++ b/Code/Tools/AssetProcessor/native/tests/AssetCatalog/AssetCatalogUnitTests.cpp @@ -766,7 +766,7 @@ namespace AssetProcessor TEST_F(AssetCatalogTest_GetFullSourcePath, AliasedCachePath_ReturnsAbsolutePathToSource) { //feed it a path with alias and asset id - QString fileToCheck = "@assets@/subfolder3/randomfileoutput.random1"; + QString fileToCheck = "@products@/subfolder3/randomfileoutput.random1"; EXPECT_TRUE(TestGetFullSourcePath(fileToCheck, m_data->m_temporarySourceDir, true, "subfolder3/somerandomfile.random")); } @@ -787,7 +787,7 @@ namespace AssetProcessor TEST_F(AssetCatalogTest_GetFullSourcePath, InvalidSourcePathContainingCacheAlias_ReturnsAbsolutePathToSource) { //feed it a path with alias and input name - QString fileToCheck = "@assets@/somerandomfile.random"; + QString fileToCheck = "@products@/somerandomfile.random"; EXPECT_TRUE(TestGetFullSourcePath(fileToCheck, m_data->m_temporarySourceDir, true, "subfolder3/somerandomfile.random")); } diff --git a/Code/Tools/AssetProcessor/native/unittests/RCcontrollerUnitTests.cpp b/Code/Tools/AssetProcessor/native/unittests/RCcontrollerUnitTests.cpp index 5b15a6a552..a8bc714698 100644 --- a/Code/Tools/AssetProcessor/native/unittests/RCcontrollerUnitTests.cpp +++ b/Code/Tools/AssetProcessor/native/unittests/RCcontrollerUnitTests.cpp @@ -47,7 +47,7 @@ void RCcontrollerUnitTests::Reset() m_rcController.m_RCJobListModel.m_jobs.clear(); m_rcController.m_RCJobListModel.m_jobsInFlight.clear(); m_rcController.m_RCJobListModel.m_jobsInQueueLookup.clear(); - + m_rcController.m_pendingCriticalJobsPerPlatform.clear(); m_rcController.m_jobsCountPerPlatform.clear(); @@ -56,7 +56,7 @@ void RCcontrollerUnitTests::Reset() m_rcController.m_RCQueueSortModel.AttachToModel(&m_rcController.m_RCJobListModel); m_rcController.m_RCQueueSortModel.m_currentJobRunKeyToJobEntries.clear(); m_rcController.m_RCQueueSortModel.m_currentlyConnectedPlatforms.clear(); -} +} void RCcontrollerUnitTests::StartTest() { @@ -183,11 +183,11 @@ void RCcontrollerUnitTests::RunRCControllerTests() QStringList tempJobNames; // Note that while this is an OS-SPECIFIC path, this test does not actually invoke the file system - // or file operators, so is purely doing in-memory testing. So the path does not actually matter and the + // or file operators, so is purely doing in-memory testing. So the path does not actually matter and the // test should function on other operating systems too. // test - exact match - tempJobNames << "c:/somerandomfolder/dev/blah/test.dds"; + tempJobNames << "c:/somerandomfolder/dev/blah/test.dds"; tempJobNames << "c:/somerandomfolder/dev/blah/test.cre"; // must not match // test - NO MATCH @@ -218,7 +218,7 @@ void RCcontrollerUnitTests::RunRCControllerTests() QList createdJobs; - + for (QString name : tempJobNames) { @@ -270,7 +270,7 @@ void RCcontrollerUnitTests::RunRCControllerTests() // EXACT MATCH TEST (with prefixes and such) NetworkRequestID requestID(1, 1234); - m_rcController.OnRequestCompileGroup(requestID, "pc", "@assets@/blah/test.dds", AZ::Data::AssetId()); + m_rcController.OnRequestCompileGroup(requestID, "pc", "@products@/blah/test.dds", AZ::Data::AssetId()); QCoreApplication::processEvents(QEventLoop::AllEvents); // this should have matched exactly one item, and when we finish that item, it should terminate: @@ -626,9 +626,9 @@ void RCcontrollerUnitTests::RunRCControllerTests() jobdetailsB.m_jobEntry.m_watchFolderPath = scanFolderInfo.ScanPath(); jobdetailsB.m_jobEntry.m_jobKey = "TestJobB"; jobdetailsB.m_jobEntry.m_builderGuid = builderUuid; - + jobdetailsB.m_critical = true; //make jobB critical so that it will be analyzed first even though we want JobA to run first - + AssetBuilderSDK::SourceFileDependency sourceFileBDependency; sourceFileBDependency.m_sourceFileDependencyPath = "fileB.txt"; @@ -694,10 +694,10 @@ void RCcontrollerUnitTests::RunRCControllerTests() m_rcController.DispatchJobs(); UNIT_TEST_EXPECT_TRUE(UnitTestUtils::BlockUntil(allJobsCompleted, 5000)); - UNIT_TEST_EXPECT_TRUE(jobFinishedB); + UNIT_TEST_EXPECT_TRUE(jobFinishedB); - // Now test the use case where we have a cyclic dependency, - // although the order in which these job will start is not defined but we can ensure that + // Now test the use case where we have a cyclic dependency, + // although the order in which these job will start is not defined but we can ensure that // all the job finishes and RCController goes Idle allJobsCompleted = false; Reset(); @@ -728,8 +728,8 @@ void RCcontrollerUnitTests::RunRCControllerTests() jobdetailsD.m_jobEntry.m_builderGuid = builderUuid; AssetBuilderSDK::SourceFileDependency sourceFileDDependency; sourceFileDDependency.m_sourceFileDependencyPath = "fileD.txt"; - - //creating cyclic job order dependencies i.e JobC and JobD have order job dependency on each other + + //creating cyclic job order dependencies i.e JobC and JobD have order job dependency on each other AssetBuilderSDK::JobDependency jobDependencyC("TestJobC", "pc", AssetBuilderSDK::JobDependencyType::Order, sourceFileCDependency); AssetBuilderSDK::JobDependency jobDependencyD("TestJobD", "pc", AssetBuilderSDK::JobDependencyType::Order, sourceFileDDependency); jobdetailsC.m_jobDependencyList.push_back({ jobDependencyD }); diff --git a/Code/Tools/AssetProcessor/native/unittests/UnitTestRunner.h b/Code/Tools/AssetProcessor/native/unittests/UnitTestRunner.h index f77c706421..c281b3050a 100644 --- a/Code/Tools/AssetProcessor/native/unittests/UnitTestRunner.h +++ b/Code/Tools/AssetProcessor/native/unittests/UnitTestRunner.h @@ -262,11 +262,10 @@ namespace UnitTestUtils AZ::IO::FileIOBase::SetInstance(m_localFileIO); - m_localFileIO->SetAlias("@assets@", (newDir + QString("/ALIAS/assets")).toUtf8().constData()); + m_localFileIO->SetAlias("@products@", (newDir + QString("/ALIAS/assets")).toUtf8().constData()); m_localFileIO->SetAlias("@log@", (newDir + QString("/ALIAS/logs")).toUtf8().constData()); m_localFileIO->SetAlias("@usercache@", (newDir + QString("/ALIAS/cache")).toUtf8().constData()); m_localFileIO->SetAlias("@user@", (newDir + QString("/ALIAS/user")).toUtf8().constData()); - m_localFileIO->SetAlias("@root@", (newDir + QString("/ALIAS/root")).toUtf8().constData()); } ~ScopedDir() diff --git a/Code/Tools/AssetProcessor/native/utilities/GUIApplicationManager.cpp b/Code/Tools/AssetProcessor/native/utilities/GUIApplicationManager.cpp index 6f974a0ff6..40d3bd3caa 100644 --- a/Code/Tools/AssetProcessor/native/utilities/GUIApplicationManager.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/GUIApplicationManager.cpp @@ -104,17 +104,17 @@ ApplicationManager::BeforeRunStatus GUIApplicationManager::BeforeRun() // The build process may leave behind some temporaries, try to delete them RemoveTemporaries(); - QDir devRoot; - AssetUtilities::ComputeAssetRoot(devRoot); + QDir projectAssetRoot; + AssetUtilities::ComputeAssetRoot(projectAssetRoot); #if defined(EXTERNAL_CRASH_REPORTING) - CrashHandler::ToolsCrashHandler::InitCrashHandler("AssetProcessor", devRoot.absolutePath().toStdString()); + CrashHandler::ToolsCrashHandler::InitCrashHandler("AssetProcessor", projectAssetRoot.absolutePath().toStdString()); #endif AssetProcessor::MessageInfoBus::Handler::BusConnect(); // we have to monitor both the cache folder and the database file and restart AP if either of them gets deleted // It is important to note that we are monitoring the parent folder and not the actual cache folder itself since // we want to handle the use case on Mac OS if the user moves the cache folder to the trash. - m_qtFileWatcher.addPath(devRoot.absolutePath()); + m_qtFileWatcher.addPath(projectAssetRoot.absolutePath()); QDir projectCacheRoot; AssetUtilities::ComputeProjectCacheRoot(projectCacheRoot); @@ -615,7 +615,6 @@ void GUIApplicationManager::DirectoryChanged([[maybe_unused]] QString path) void GUIApplicationManager::FileChanged(QString path) { - QDir devRoot = ApplicationManager::GetSystemRoot(); QDir projectCacheRoot; AssetUtilities::ComputeProjectCacheRoot(projectCacheRoot); QString assetDbPath = projectCacheRoot.filePath("assetdb.sqlite"); diff --git a/Code/Tools/CrashHandler/Tools/ToolsCrashHandler.cpp b/Code/Tools/CrashHandler/Tools/ToolsCrashHandler.cpp index 527feac6b4..2cf7705e96 100644 --- a/Code/Tools/CrashHandler/Tools/ToolsCrashHandler.cpp +++ b/Code/Tools/CrashHandler/Tools/ToolsCrashHandler.cpp @@ -56,7 +56,7 @@ namespace CrashHandler if (fileIO) { // If our devroot alias is available, use that - const char* devAlias = fileIO->GetAlias("@devroot@"); + const char* devAlias = fileIO->GetAlias("@engroot@"); if (devAlias) { return devAlias; diff --git a/Code/Tools/PythonBindingsExample/tests/ApplicationTests.cpp b/Code/Tools/PythonBindingsExample/tests/ApplicationTests.cpp index 91ca77fa7b..c7d85428b4 100644 --- a/Code/Tools/PythonBindingsExample/tests/ApplicationTests.cpp +++ b/Code/Tools/PythonBindingsExample/tests/ApplicationTests.cpp @@ -87,7 +87,7 @@ namespace PythonBindingsExample TEST_F(PythonBindingsExampleTest, Application_ImportAzLmbrPaths_Works) { ApplicationParameters params; - params.m_pythonStatement = "import azlmbr.paths; print (azlmbr.paths.engroot); print (azlmbr.paths.devroot)"; + params.m_pythonStatement = "import azlmbr.paths; print (azlmbr.paths.engroot)"; EXPECT_TRUE(s_application->RunWithParameters(params)); } diff --git a/Code/Tools/SceneAPI/SceneCore/Export/MtlMaterialExporter.cpp b/Code/Tools/SceneAPI/SceneCore/Export/MtlMaterialExporter.cpp index aaa76e5977..aa88dee90f 100644 --- a/Code/Tools/SceneAPI/SceneCore/Export/MtlMaterialExporter.cpp +++ b/Code/Tools/SceneAPI/SceneCore/Export/MtlMaterialExporter.cpp @@ -14,8 +14,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -170,11 +172,14 @@ namespace AZ { using AzToolsFramework::AssetSystemRequestBus; - const char* path = nullptr; - AssetSystemRequestBus::BroadcastResult(path, &AssetSystemRequestBus::Events::GetAbsoluteDevGameFolderPath); - if (path) + AZ::IO::Path projectPath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) { - return path; + settingsRegistry->Get(projectPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath); + } + if (!projectPath.empty()) + { + return projectPath.Native(); } else { diff --git a/Code/Tools/SerializeContextTools/SliceConverter.cpp b/Code/Tools/SerializeContextTools/SliceConverter.cpp index c815af3b7a..6cfe072f80 100644 --- a/Code/Tools/SerializeContextTools/SliceConverter.cpp +++ b/Code/Tools/SerializeContextTools/SliceConverter.cpp @@ -38,7 +38,7 @@ // SliceConverter reads in a slice file (saved in an ObjectStream format), instantiates it, creates a prefab out of the data, // and saves the prefab in a JSON format. This can be used for one-time migrations of slices or slice-based levels to prefabs. -// +// // If the slice contains legacy data, it will print out warnings / errors about the data that couldn't be serialized. // The prefab will be generated without that data. @@ -56,7 +56,7 @@ namespace AZ AZ_Error("SerializeContextTools", false, "Command line not available."); return false; } - + JsonSerializerSettings convertSettings; convertSettings.m_keepDefaults = commandLine->HasSwitch("keepdefaults"); convertSettings.m_registrationContext = application.GetJsonRegistrationContext(); @@ -82,7 +82,7 @@ namespace AZ // Load the asset catalog so that we can find any nested assets successfully. We also need to tick the tick bus // so that the OnCatalogLoaded event gets processed now, instead of during application shutdown. AZ::Data::AssetCatalogRequestBus::Broadcast( - &AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, "@assets@/assetcatalog.xml"); + &AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, "@products@/assetcatalog.xml"); application.Tick(); AZStd::string logggingScratchBuffer; @@ -870,7 +870,7 @@ namespace AZ // Wait for the disconnect to finish. bool disconnected = false; - AzFramework::AssetSystemRequestBus::BroadcastResult(disconnected, + AzFramework::AssetSystemRequestBus::BroadcastResult(disconnected, &AzFramework::AssetSystem::AssetSystemRequests::WaitUntilAssetProcessorDisconnected, AZStd::chrono::seconds(30)); AZ_Error("Convert-Slice", disconnected, "Asset Processor failed to disconnect successfully."); diff --git a/Gems/AWSCore/Code/Source/Configuration/AWSCoreConfiguration.cpp b/Gems/AWSCore/Code/Source/Configuration/AWSCoreConfiguration.cpp index 4653975a52..d51539a471 100644 --- a/Gems/AWSCore/Code/Source/Configuration/AWSCoreConfiguration.cpp +++ b/Gems/AWSCore/Code/Source/Configuration/AWSCoreConfiguration.cpp @@ -64,7 +64,7 @@ namespace AWSCore void AWSCoreConfiguration::InitSourceProjectFolderPath() { - auto sourceProjectFolder = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@"); + auto sourceProjectFolder = AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@"); if (!sourceProjectFolder) { AZ_Error(AWSCoreConfigurationName, false, ProjectSourceFolderNotFoundErrorMessage); diff --git a/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreEditorMenu.cpp b/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreEditorMenu.cpp index a2c89a5af3..0b485609ad 100644 --- a/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreEditorMenu.cpp +++ b/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreEditorMenu.cpp @@ -197,7 +197,7 @@ namespace AWSCore subMenu->addAction(AddExternalLinkAction( AWSMetricsAdvancedTopicsActionText, AWSMetricsAdvancedTopicsUrl, ":/Notifications/link.svg")); - AZStd::string priorAlias = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devroot@"); + AZStd::string priorAlias = AZ::IO::FileIOBase::GetInstance()->GetAlias("@engroot@"); AZStd::string configFilePath = priorAlias + "\\Gems\\AWSMetrics\\Code\\" + AZ::SettingsRegistryInterface::RegistryFolder; AzFramework::StringFunc::Path::Normalize(configFilePath); diff --git a/Gems/AWSCore/Code/Tests/Configuration/AWSCoreConfigurationTest.cpp b/Gems/AWSCore/Code/Tests/Configuration/AWSCoreConfigurationTest.cpp index 6bde2c2fbf..e54a55f728 100644 --- a/Gems/AWSCore/Code/Tests/Configuration/AWSCoreConfigurationTest.cpp +++ b/Gems/AWSCore/Code/Tests/Configuration/AWSCoreConfigurationTest.cpp @@ -60,7 +60,7 @@ public: m_normalizedSourceProjectFolder.c_str(), AZ::SettingsRegistryInterface::RegistryFolder); AzFramework::StringFunc::Path::Normalize(m_normalizedSetRegFolderPath); - m_localFileIO->SetAlias("@devassets@", m_normalizedSourceProjectFolder.c_str()); + m_localFileIO->SetAlias("@projectroot@", m_normalizedSourceProjectFolder.c_str()); CreateTestSetRegFile(TEST_VALID_RESOURCE_MAPPING_SETREG); } @@ -122,7 +122,7 @@ private: TEST_F(AWSCoreConfigurationTest, InitConfig_NoSourceProjectFolderFound_ReturnEmptyConfigFilePath) { m_settingsRegistry->MergeSettingsFile(m_normalizedSetRegFilePath, AZ::SettingsRegistryInterface::Format::JsonMergePatch, {}); - m_localFileIO->ClearAlias("@devassets@"); + m_localFileIO->ClearAlias("@projectroot@"); AZ_TEST_START_TRACE_SUPPRESSION; m_awsCoreConfiguration->InitConfig(); @@ -154,7 +154,7 @@ TEST_F(AWSCoreConfigurationTest, InitConfig_LoadValidSettingsRegistry_ReturnNonE TEST_F(AWSCoreConfigurationTest, ReloadConfiguration_NoSourceProjectFolderFound_ReturnEmptyConfigFilePath) { m_settingsRegistry->MergeSettingsFile(m_normalizedSetRegFilePath, AZ::SettingsRegistryInterface::Format::JsonMergePatch, {}); - m_localFileIO->ClearAlias("@devassets@"); + m_localFileIO->ClearAlias("@projectroot@"); m_awsCoreConfiguration->ReloadConfiguration(); auto actualConfigFilePath = m_awsCoreConfiguration->GetResourceMappingConfigFilePath(); diff --git a/Gems/AWSCore/Code/Tests/Editor/UI/AWSCoreEditorMenuTest.cpp b/Gems/AWSCore/Code/Tests/Editor/UI/AWSCoreEditorMenuTest.cpp index 40ed5b53b5..e9453a4a0a 100644 --- a/Gems/AWSCore/Code/Tests/Editor/UI/AWSCoreEditorMenuTest.cpp +++ b/Gems/AWSCore/Code/Tests/Editor/UI/AWSCoreEditorMenuTest.cpp @@ -32,7 +32,7 @@ class AWSCoreEditorMenuTest { AWSCoreEditorUIFixture::SetUp(); AWSCoreFixture::SetUp(); - m_localFileIO->SetAlias("@devroot@", "dummy engine root"); + m_localFileIO->SetAlias("@engroot@", "dummy engine root"); } void TearDown() override diff --git a/Gems/AWSMetrics/Code/Source/IdentityProvider.cpp b/Gems/AWSMetrics/Code/Source/IdentityProvider.cpp index 7e4ec05aba..bc8ff9a42e 100644 --- a/Gems/AWSMetrics/Code/Source/IdentityProvider.cpp +++ b/Gems/AWSMetrics/Code/Source/IdentityProvider.cpp @@ -22,7 +22,7 @@ namespace AWSMetrics AZStd::string IdentityProvider::GetEngineVersion() { - static constexpr const char* EngineConfigFilePath = "@root@/engine.json"; + static constexpr const char* EngineConfigFilePath = "@products@/engine.json"; static constexpr const char* EngineVersionJsonKey = "O3DEVersion"; AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetDirectInstance(); diff --git a/Gems/AWSMetrics/Code/Tests/AWSMetricsGemMock.h b/Gems/AWSMetrics/Code/Tests/AWSMetricsGemMock.h index 6b7c809601..b77f39c93c 100644 --- a/Gems/AWSMetrics/Code/Tests/AWSMetricsGemMock.h +++ b/Gems/AWSMetrics/Code/Tests/AWSMetricsGemMock.h @@ -16,8 +16,8 @@ #include #include #include +#include #include -#include namespace AWSMetrics { @@ -34,15 +34,22 @@ namespace AWSMetrics // Set up the file IO and alias m_localFileIO = aznew AZ::IO::LocalFileIO(); m_priorFileIO = AZ::IO::FileIOBase::GetInstance(); - // we need to set it to nullptr first because otherwise the + // we need to set it to nullptr first because otherwise the // underneath code assumes that we might be leaking the previous instance AZ::IO::FileIOBase::SetInstance(nullptr); AZ::IO::FileIOBase::SetInstance(m_localFileIO); - const AZStd::string engineRoot = AZ::Test::GetEngineRootPath(); - m_localFileIO->SetAlias("@devroot@", engineRoot.c_str()); - m_localFileIO->SetAlias("@root@", engineRoot.c_str()); - m_localFileIO->SetAlias("@user@", GetTestFolderPath().c_str()); + const AZ::IO::Path engineRoot = AZ::Test::GetEngineRootPath(); + const auto productAssetPath = GetTestFolderPath() / "Cache"; + const auto userPath = GetTestFolderPath() / "user"; + m_localFileIO->CreatePath(productAssetPath.c_str()); + m_localFileIO->CreatePath(userPath.c_str()); + m_localFileIO->SetAlias("@engroot@", engineRoot.c_str()); + m_localFileIO->SetAlias("@products@", productAssetPath.c_str()); + m_localFileIO->SetAlias("@user@", userPath.c_str()); + // Copy engine.json to the cache + EXPECT_TRUE(m_localFileIO->Copy((engineRoot / "engine.json").c_str(), "engine.json")); + m_serializeContext = AZStd::make_unique(); m_registrationContext = AZStd::make_unique(); @@ -69,6 +76,13 @@ namespace AWSMetrics m_serializeContext.reset(); m_registrationContext.reset(); + const auto productAssetPath = GetTestFolderPath() / "Cache"; + const auto userPath = GetTestFolderPath() / "user"; + // Clear the product asset cache alias to prevent cache write errors + m_localFileIO->ClearAlias("@products@"); + m_localFileIO->DestroyPath(userPath.c_str()); + m_localFileIO->DestroyPath(productAssetPath.c_str()); + AZ::IO::FileIOBase::SetInstance(nullptr); delete m_localFileIO; AZ::IO::FileIOBase::SetInstance(m_priorFileIO); @@ -97,22 +111,22 @@ namespace AWSMetrics bool CreateFile(const AZStd::string& filePath, const AZStd::string& content) { AZ::IO::HandleType fileHandle; + // Suppress errors about writing to product asset cache + AZ_TEST_START_TRACE_SUPPRESSION; if (!m_localFileIO->Open(filePath.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText, fileHandle)) { return false; } m_localFileIO->Write(fileHandle, content.c_str(), content.size()); + AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; m_localFileIO->Close(fileHandle); return true; } AZStd::string GetDefaultTestFilePath() { - AZStd::string testFilePath = GetTestFolderPath(); - AzFramework::StringFunc::Path::Join(testFilePath.c_str(), "Test.json", testFilePath); - - return testFilePath; + return (GetTestFolderPath() / "Test.json").Native(); } bool RemoveFile(const AZStd::string& filePath) @@ -133,14 +147,16 @@ namespace AWSMetrics AZ::IO::FileIOBase* m_priorFileIO = nullptr; AZ::IO::FileIOBase* m_localFileIO = nullptr; + AZ::Test::ScopedAutoTempDirectory m_testDirectory; AZStd::unique_ptr m_serializeContext; AZStd::unique_ptr m_registrationContext; AZStd::unique_ptr m_settingsRegistry; private: - AZStd::string GetTestFolderPath() + AZ::IO::Path GetTestFolderPath() { - return AZ_TRAIT_TEST_ROOT_FOLDER; + AZ::IO::Path testPathString{ m_testDirectory.GetDirectory() }; + return testPathString; } }; } diff --git a/Gems/AssetValidation/Code/Source/AssetValidationSystemComponent.cpp b/Gems/AssetValidation/Code/Source/AssetValidationSystemComponent.cpp index b4bf68bac1..56f28856af 100644 --- a/Gems/AssetValidation/Code/Source/AssetValidationSystemComponent.cpp +++ b/Gems/AssetValidation/Code/Source/AssetValidationSystemComponent.cpp @@ -142,14 +142,14 @@ namespace AssetValidation system.GetIConsole()->AddCommand("addseedlist", ConsoleCommandAddSeedList); system.GetIConsole()->AddCommand("removeseedlist", ConsoleCommandRemoveSeedList); system.GetIConsole()->AddCommand("printexcluded", ConsoleCommandTogglePrintExcluded); - } + } bool AssetValidationSystemComponent::IsKnownAsset(const char* assetPath) { AZStd::string lowerAsset{ assetPath }; AZStd::replace(lowerAsset.begin(), lowerAsset.end(), AZ_WRONG_DATABASE_SEPARATOR, AZ_CORRECT_DATABASE_SEPARATOR); - const AZStd::vector prefixes = { "./", "@assets@/" }; + const AZStd::vector prefixes = { "./", "@products@/" }; for (const AZStd::string& prefix : prefixes) { if (lowerAsset.starts_with(prefix)) @@ -392,7 +392,7 @@ namespace AssetValidation AssetValidationRequestBus::Broadcast(&AssetValidationRequestBus::Events::AddSeedList, seedfilepath); } - bool AssetValidationSystemComponent::AddSeedsFor(const AzFramework::AssetSeedList& seedList, AZ::u32 seedId) + bool AssetValidationSystemComponent::AddSeedsFor(const AzFramework::AssetSeedList& seedList, AZ::u32 seedId) { for (const AzFramework::SeedInfo& thisSeed : seedList) { @@ -401,7 +401,7 @@ namespace AssetValidation return true; } - bool AssetValidationSystemComponent::RemoveSeedsFor(const AzFramework::AssetSeedList& seedList, AZ::u32 seedId) + bool AssetValidationSystemComponent::RemoveSeedsFor(const AzFramework::AssetSeedList& seedList, AZ::u32 seedId) { AssetValidationRequests::AssetSourceList removeList; for (const AzFramework::SeedInfo& thisSeed : seedList) diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.cpp index 3493099d4c..924c01b916 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.cpp @@ -244,7 +244,7 @@ namespace ImageProcessingAtom } AZ::IO::FixedMaxPath projectConfigFolder; - if (auto sourceGameRoot = fileIoBase->ResolvePath("@devassets@"); sourceGameRoot.has_value()) + if (auto sourceGameRoot = fileIoBase->ResolvePath("@projectroot@"); sourceGameRoot.has_value()) { projectConfigFolder = *sourceGameRoot; projectConfigFolder /= s_projectConfigRelativeFolder; diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp index 7c5be89508..27ae90dcdc 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp @@ -139,16 +139,16 @@ namespace AZ //! Validates if a given .shadervariantlist file is located at the correct path for a given .shader full path. //! There are two valid paths: //! 1- Lower Precedence: The same folder where the .shader file is located. - //! 2- Higher Precedence: //ShaderVariants/. + //! 2- Higher Precedence: /ShaderVariants/. //! The "Higher Precedence" path gives the option to game projects to override what variants to generate. If this //! file exists then the "Lower Precedence" path is disregarded. //! A .shader full path is located under an AP scan folder. - //! Example: "/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.shader" - //! - In this example the Scan Folder is "/Gems/Atom/Feature/Common/Assets", while the subfolder is "Materials/Types". + //! Example: "/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.shader" + //! - In this example the Scan Folder is "/Gems/Atom/Feature/Common/Assets", while the subfolder is "Materials/Types". //! The "Higher Precedence" expected valid location for the .shadervariantlist would be: - //! - //ShaderVariants/Materials/Types/StandardPBR_ForwardPass.shadervariantlist. + //! - //ShaderVariants/Materials/Types/StandardPBR_ForwardPass.shadervariantlist. //! The "Lower Precedence" valid location would be: - //! - /Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.shadervariantlist. + //! - /Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.shadervariantlist. //! @shouldExitEarlyFromProcessJob [out] Set to true if ProcessJob should do no work but return successfully. //! Set to false if ProcessJob should do work and create assets. //! When @shaderVariantListFileFullPath is provided by a Gem/Feature instead of the Game Project @@ -169,17 +169,13 @@ namespace AZ AZStd::string shaderVariantListFileRelativePath = shaderProductFileRelativePath; AzFramework::StringFunc::Path::ReplaceExtension(shaderVariantListFileRelativePath, RPI::ShaderVariantListSourceData::Extension); - const char * gameProjectPath = nullptr; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(gameProjectPath, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetAbsoluteDevGameFolderPath); + AZ::IO::FixedMaxPath gameProjectPath = AZ::Utils::GetProjectPath(); - AZStd::string expectedHigherPrecedenceFileFullPath; - AzFramework::StringFunc::Path::Join(gameProjectPath, RPI::ShaderVariantTreeAsset::CommonSubFolder, expectedHigherPrecedenceFileFullPath, false /* handle directory overlap? */, false /* be case insensitive? */); - AzFramework::StringFunc::Path::Join(expectedHigherPrecedenceFileFullPath.c_str(), shaderProductFileRelativePath.c_str(), expectedHigherPrecedenceFileFullPath, false /* handle directory overlap? */, false /* be case insensitive? */); - AzFramework::StringFunc::Path::ReplaceExtension(expectedHigherPrecedenceFileFullPath, AZ::RPI::ShaderVariantListSourceData::Extension); - AzFramework::StringFunc::Path::Normalize(expectedHigherPrecedenceFileFullPath); + auto expectedHigherPrecedenceFileFullPath = (gameProjectPath + / RPI::ShaderVariantTreeAsset::CommonSubFolder / shaderProductFileRelativePath).LexicallyNormal(); + expectedHigherPrecedenceFileFullPath.ReplaceExtension(AZ::RPI::ShaderVariantListSourceData::Extension); - AZStd::string normalizedShaderVariantListFileFullPath = shaderVariantListFileFullPath; - AzFramework::StringFunc::Path::Normalize(normalizedShaderVariantListFileFullPath); + auto normalizedShaderVariantListFileFullPath = AZ::IO::FixedMaxPath(shaderVariantListFileFullPath).LexicallyNormal(); if (expectedHigherPrecedenceFileFullPath == normalizedShaderVariantListFileFullPath) { @@ -203,23 +199,15 @@ namespace AZ } // Check the "Lower Precedence" case, .shader path == .shadervariantlist path. - AZStd::string normalizedShaderFileFullPath = shaderFileFullPath; - AzFramework::StringFunc::Path::Normalize(normalizedShaderFileFullPath); + AZ::IO::Path normalizedShaderFileFullPath = AZ::IO::Path(shaderFileFullPath).LexicallyNormal(); - AZStd::string normalizedShaderFileFullPathWithoutExtension = normalizedShaderFileFullPath; - AzFramework::StringFunc::Path::StripExtension(normalizedShaderFileFullPathWithoutExtension); + auto normalizedShaderFileFullPathWithoutExtension = normalizedShaderFileFullPath; + normalizedShaderFileFullPathWithoutExtension.ReplaceExtension(""); - AZStd::string normalizedShaderVariantListFileFullPathWithoutExtension = normalizedShaderVariantListFileFullPath; - AzFramework::StringFunc::Path::StripExtension(normalizedShaderVariantListFileFullPathWithoutExtension); + auto normalizedShaderVariantListFileFullPathWithoutExtension = normalizedShaderVariantListFileFullPath; + normalizedShaderVariantListFileFullPathWithoutExtension.ReplaceExtension(""); -#if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS - //In certain circumstances, the capitalization of the drive letter may not match - const bool caseSensitive = false; -#else - //On the other platforms there's no drive letter, so it should be a non-issue. - const bool caseSensitive = true; -#endif - if (!StringFunc::Equal(normalizedShaderFileFullPathWithoutExtension.c_str(), normalizedShaderVariantListFileFullPathWithoutExtension.c_str(), caseSensitive)) + if (normalizedShaderFileFullPathWithoutExtension != normalizedShaderVariantListFileFullPathWithoutExtension) { AZ_Error(ShaderVariantAssetBuilderName, false, "For shader file at path [%s], the shader variant list [%s] is expected to be located at [%s.%s] or [%s]" , normalizedShaderFileFullPath.c_str(), normalizedShaderVariantListFileFullPath.c_str(), diff --git a/Gems/Atom/RHI/Code/Tests/UtilsTests.cpp b/Gems/Atom/RHI/Code/Tests/UtilsTests.cpp index 8495e9b119..27336c8280 100644 --- a/Gems/Atom/RHI/Code/Tests/UtilsTests.cpp +++ b/Gems/Atom/RHI/Code/Tests/UtilsTests.cpp @@ -28,7 +28,7 @@ namespace UnitTest m_application.reset(); } - static constexpr const char TestDataFolder[] = "@devroot@/Gems/Atom/RHI/Code/Tests/UtilsTestsData/"; + static constexpr const char TestDataFolder[] = "@engroot@/Gems/Atom/RHI/Code/Tests/UtilsTestsData/"; AZStd::unique_ptr m_application; }; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Common/AssetUtils.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Common/AssetUtils.h index 341824a84d..bd11965ffa 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Common/AssetUtils.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Common/AssetUtils.h @@ -44,14 +44,14 @@ namespace AZ AZStd::string GetSourcePathByAssetId(const AZ::Data::AssetId& assetId); //! Tries to resolve a relative file reference, given the path of a referencing file. - //! @param originatingSourceFilePath Path to the parent file that references referencedSourceFilePath. May be absolute or relative to asset-root. + //! @param originatingSourceFilePath Path to the parent file that references referencedSourceFilePath. May be absolute or relative to asset-root. //! @param referencedSourceFilePath Path that the parent file references. May be relative to the parent file location or relative to asset-root. //! @return A full path for referencedSourceFilePath, if a full path was found. If a full path could not be constructed, returns referencedSourceFilePath unmodified. AZStd::string ResolvePathReference(const AZStd::string& originatingSourceFilePath, const AZStd::string& referencedSourceFilePath); - //! Returns the list of paths where a source asset file could possibly appear. + //! Returns the list of paths where a source asset file could possibly appear. //! This is intended for use by AssetBuilders when reporting dependencies, to support relative paths between source files. - //! When a source data file references another file using a relative path, the path might be relative to the originating + //! When a source data file references another file using a relative path, the path might be relative to the originating //! file or it might be a standard source asset path (i.e. relative to the logical asset-root). This function will help reporting //! dependencies on all possible locations where that file may appear at some point in the future. //! For example a file MyGem/Assets/Foo/a.json might reference another file as "Bar/b.json". In this case, calling @@ -94,9 +94,9 @@ namespace AZ template Outcome> LoadAsset(const AZ::Data::AssetId& assetId, [[maybe_unused]] const char* sourcePathForDebug) { - if (nullptr == AZ::IO::FileIOBase::GetInstance()->GetAlias("@assets@")) + if (nullptr == AZ::IO::FileIOBase::GetInstance()->GetAlias("@products@")) { - // The absence of "@assets@" is not necessarily the reason LoadAsset() can't be used in CreateJobs(), but it + // The absence of "@products@" is not necessarily the reason LoadAsset() can't be used in CreateJobs(), but it // is a symptom of calling LoadAsset() from CreateJobs() which is not supported. AZ_Assert(false, "It appears AssetUtils::LoadAsset() is being called in CreateJobs(). It can only be used in ProcessJob()."); return AZ::Failure(); diff --git a/Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.cpp b/Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.cpp index 63a1524929..a5511edea1 100644 --- a/Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.cpp +++ b/Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.cpp @@ -53,16 +53,6 @@ namespace UnitTest return false; } - const char* AssetSystemStub::GetAbsoluteDevGameFolderPath() - { - return nullptr; - } - - const char* AssetSystemStub::GetAbsoluteDevRootFolderPath() - { - return nullptr; - } - bool AssetSystemStub::GetRelativeProductPathFromFullSourceOrProductPath([[maybe_unused]] const AZStd::string& fullPath, [[maybe_unused]] AZStd::string& relativeProductPath) { return false; diff --git a/Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.h b/Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.h index a73570e3c9..2dd810b1e6 100644 --- a/Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.h +++ b/Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.h @@ -56,8 +56,6 @@ namespace UnitTest AZStd::unordered_map m_sourceInfoMap; bool GetSourceInfoBySourcePath(const char* sourcePath, AZ::Data::AssetInfo& assetInfo, AZStd::string& watchFolder) override; - const char* GetAbsoluteDevGameFolderPath() override; - const char* GetAbsoluteDevRootFolderPath() override; bool GetRelativeProductPathFromFullSourceOrProductPath(const AZStd::string& fullPath, AZStd::string& relativeProductPath) override; bool GenerateRelativeSourcePath( const AZStd::string& sourcePath, AZStd::string& relativePath, AZStd::string& watchFolder) override; diff --git a/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.cpp b/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.cpp index aaa574a14a..5343c295d8 100644 --- a/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.cpp +++ b/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.cpp @@ -67,7 +67,7 @@ namespace UnitTest AZ::IO::Path assetPath = AZStd::string_view{ AZ::Utils::GetProjectPath() }; assetPath /= "Cache"; - AZ::IO::FileIOBase::GetInstance()->SetAlias("@assets@", assetPath.c_str()); + AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", assetPath.c_str()); m_jsonRegistrationContext = AZStd::make_unique(); m_jsonSystemComponent = AZStd::make_unique(); @@ -90,7 +90,7 @@ namespace UnitTest JobManagerThreadDesc threadDesc; #if AZ_TRAIT_SET_JOB_PROCESSOR_ID threadDesc.m_cpuId = 0; // Don't set processors IDs on windows -#endif +#endif uint32_t numWorkerThreads = AZStd::thread::hardware_concurrency(); @@ -99,7 +99,7 @@ namespace UnitTest desc.m_workerThreads.push_back(threadDesc); #if AZ_TRAIT_SET_JOB_PROCESSOR_ID threadDesc.m_cpuId++; -#endif +#endif } m_jobManager = AZStd::make_unique(desc); diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp index 13b9a2ba27..3fae2ee7a3 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp @@ -173,7 +173,7 @@ namespace AtomToolsFramework AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotificationBus::Broadcast( &AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotifications::OnDatabaseInitialized); - AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, "@assets@/assetcatalog.xml"); + AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, "@products@/assetcatalog.xml"); if (!AZ::RPI::RPISystemInterface::Get()->IsInitialized()) { @@ -289,7 +289,7 @@ namespace AtomToolsFramework ExitMainLoop(); } } - + void AtomToolsApplication::SaveSettings() { if (m_activatedLocalUserSettings) @@ -378,7 +378,7 @@ namespace AtomToolsFramework ExitMainLoop(); } } - + bool AtomToolsApplication::LaunchLocalServer() { // Determine if this is the first launch of the tool by attempting to connect to a running server diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/CreateMaterialDialog/CreateMaterialDialog.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/CreateMaterialDialog/CreateMaterialDialog.cpp index f27a08b08d..fd20716570 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/CreateMaterialDialog/CreateMaterialDialog.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/CreateMaterialDialog/CreateMaterialDialog.cpp @@ -24,7 +24,7 @@ namespace MaterialEditor { CreateMaterialDialog::CreateMaterialDialog(QWidget* parent) - : CreateMaterialDialog(QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@")) + AZ_CORRECT_FILESYSTEM_SEPARATOR + "Materials", parent) + : CreateMaterialDialog(QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@")) + AZ_CORRECT_FILESYSTEM_SEPARATOR + "Materials", parent) { } diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorBrowserInteractions.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorBrowserInteractions.cpp index e6ffd2842f..d73737a2dc 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorBrowserInteractions.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorBrowserInteractions.cpp @@ -106,7 +106,7 @@ namespace MaterialEditor menu->addAction("Create Material...", [entry]() { const QString defaultPath = AtomToolsFramework::GetUniqueFileInfo( - QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@")) + + QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@")) + AZ_CORRECT_FILESYSTEM_SEPARATOR + "Materials" + AZ_CORRECT_FILESYSTEM_SEPARATOR + "untitled." + AZ::RPI::MaterialSourceData::Extension).absoluteFilePath(); @@ -182,7 +182,7 @@ namespace MaterialEditor menu->addAction("Create Child Material...", [entry]() { const QString defaultPath = AtomToolsFramework::GetUniqueFileInfo( - QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@")) + + QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@")) + AZ_CORRECT_FILESYSTEM_SEPARATOR + "Materials" + AZ_CORRECT_FILESYSTEM_SEPARATOR + "untitled." + AZ::RPI::MaterialSourceData::Extension).absoluteFilePath(); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp index a00d3eec05..5721dfcc72 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp @@ -346,7 +346,7 @@ namespace MaterialEditor AZStd::string ViewportSettingsInspector::GetDefaultUniqueSaveFilePath(const AZStd::string& baseName) const { - AZStd::string savePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@"); + AZStd::string savePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@"); savePath += AZ_CORRECT_FILESYSTEM_SEPARATOR; savePath += "Materials"; savePath += AZ_CORRECT_FILESYSTEM_SEPARATOR; diff --git a/Gems/Atom/Tools/MaterialEditor/Scripts/GenerateAllMaterialScreenshots.py b/Gems/Atom/Tools/MaterialEditor/Scripts/GenerateAllMaterialScreenshots.py index 6708553e20..041e1a80c5 100755 --- a/Gems/Atom/Tools/MaterialEditor/Scripts/GenerateAllMaterialScreenshots.py +++ b/Gems/Atom/Tools/MaterialEditor/Scripts/GenerateAllMaterialScreenshots.py @@ -16,10 +16,10 @@ import sys import os.path import filecmp -g_devroot = azlmbr.paths.devroot -sys.path.append(os.path.join(g_devroot, 'Tests', 'Atom', 'Automated')) +g_engroot = azlmbr.paths.engroot +sys.path.append(os.path.join(g_engroot, 'Tests', 'Atom', 'Automated')) -g_materialTestFolder = os.path.join(g_devroot,'Gems','Atom','TestData','TestData','Materials','StandardPbrTestCases') +g_materialTestFolder = os.path.join(g_engroot,'Gems','Atom','TestData','TestData','Materials','StandardPbrTestCases') # Change this to True to replace the expected screenshot images g_replaceExpectedScreenshots = False diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Scripts/GenerateShaderVariantListForMaterials.py b/Gems/Atom/Tools/ShaderManagementConsole/Scripts/GenerateShaderVariantListForMaterials.py index 7bd65568ed..c31047d347 100755 --- a/Gems/Atom/Tools/ShaderManagementConsole/Scripts/GenerateShaderVariantListForMaterials.py +++ b/Gems/Atom/Tools/ShaderManagementConsole/Scripts/GenerateShaderVariantListForMaterials.py @@ -135,7 +135,7 @@ def main(): # clean previously generated shader variant list file so they don't clash. pre, ext = os.path.splitext(shaderAssetInfo.relativePath) - projectShaderVariantListFilePath = os.path.join(azlmbr.paths.devassets, PROJECT_SHADER_VARIANTS_FOLDER, f'{pre}.shadervariantlist') + projectShaderVariantListFilePath = os.path.join(azlmbr.paths.projectroot, PROJECT_SHADER_VARIANTS_FOLDER, f'{pre}.shadervariantlist') pre, ext = os.path.splitext(filename) defaultShaderVariantListFilePath = f'{pre}.shadervariantlist' diff --git a/Gems/AtomLyIntegration/AtomFont/Code/Source/AtomFont.cpp b/Gems/AtomLyIntegration/AtomFont/Code/Source/AtomFont.cpp index 5711e3ff6e..cdb941546d 100644 --- a/Gems/AtomLyIntegration/AtomFont/Code/Source/AtomFont.cpp +++ b/Gems/AtomLyIntegration/AtomFont/Code/Source/AtomFont.cpp @@ -46,7 +46,7 @@ static void DumfontTexture(IConsoleCmdArgs* cmdArgs) if (fontName && *fontName && *fontName != '0') { - AZStd::string fontFilePath("@devroot@/"); + AZStd::string fontFilePath("@engroot@/"); fontFilePath += fontName; fontFilePath += ".bmp"; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp index 7f676e4c10..4363ac1a62 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp @@ -389,7 +389,7 @@ namespace AZ // create the full paths char projectPath[AZ_MAX_PATH_LEN]; - AZ::IO::FileIOBase::GetInstance()->ResolvePath("@devassets@", projectPath, AZ_MAX_PATH_LEN); + AZ::IO::FileIOBase::GetInstance()->ResolvePath("@projectroot@", projectPath, AZ_MAX_PATH_LEN); AZStd::string irradianceTextureFullPath; AzFramework::StringFunc::Path::Join(projectPath, irradianceTextureRelativePath.c_str(), irradianceTextureFullPath, true, true); @@ -481,7 +481,7 @@ namespace AZ AZStd::string fullPath; char projectPath[AZ_MAX_PATH_LEN]; - AZ::IO::FileIOBase::GetInstance()->ResolvePath("@devassets@", projectPath, AZ_MAX_PATH_LEN); + AZ::IO::FileIOBase::GetInstance()->ResolvePath("@projectroot@", projectPath, AZ_MAX_PATH_LEN); if (!relativePath.empty()) { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp index 095c670e15..665adcd568 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp @@ -529,7 +529,7 @@ namespace AZ bool MaterialPropertyInspector::SaveMaterial() const { const QString defaultPath = AtomToolsFramework::GetUniqueFileInfo( - QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@")) + + QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@")) + AZ_CORRECT_FILESYSTEM_SEPARATOR + "Materials" + AZ_CORRECT_FILESYSTEM_SEPARATOR + "untitled." + AZ::RPI::MaterialSourceData::Extension).absoluteFilePath(); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp index d7fcd124d0..f325a20ac1 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/ReflectionProbe/EditorReflectionProbeComponent.cpp @@ -321,7 +321,7 @@ namespace AZ } char projectPath[AZ_MAX_PATH_LEN]; - AZ::IO::FileIOBase::GetInstance()->ResolvePath("@devassets@", projectPath, AZ_MAX_PATH_LEN); + AZ::IO::FileIOBase::GetInstance()->ResolvePath("@projectroot@", projectPath, AZ_MAX_PATH_LEN); // retrieve the source cubemap path from the configuration // we need to make sure to use the same source cubemap for each bake diff --git a/Gems/AudioEngineWwise/Code/Source/Builder/AudioControlBuilderWorker.cpp b/Gems/AudioEngineWwise/Code/Source/Builder/AudioControlBuilderWorker.cpp index a31885cc69..2fe5d749cf 100644 --- a/Gems/AudioEngineWwise/Code/Source/Builder/AudioControlBuilderWorker.cpp +++ b/Gems/AudioEngineWwise/Code/Source/Builder/AudioControlBuilderWorker.cpp @@ -105,7 +105,7 @@ namespace AudioControlBuilder Audio::ATLXmlTags::ATLPreloadRequestTag, "preload request")); } - // For each preload request in the control file, determine which config group is used for this platform and register each + // For each preload request in the control file, determine which config group is used for this platform and register each // bank listed in that preload request as a dependency. while (preloadRequestNode) { @@ -163,7 +163,7 @@ namespace AudioControlBuilder const AZ::rapidxml::xml_node* configGroupNode = configGroupMap[configGroupName]; if (!configGroupNode) { - // The config group this platform uses isn't defined in the control file. This might be intentional, so just + // The config group this platform uses isn't defined in the control file. This might be intentional, so just // generate a warning and keep going to the next preload node. AZ_TracePrintf("Audio Control Builder", "%s node for config group %s is not defined, so no banks are referenced.", Audio::ATLXmlTags::ATLConfigGroupTag, configGroupName.c_str()); @@ -188,7 +188,7 @@ namespace AudioControlBuilder } // Prepend the bank name with the relative path to the wwise sounds folder to get relative path to the bank from - // the @assets@ alias and push that into the list of banks referenced. + // the @products@ alias and push that into the list of banks referenced. AZStd::string soundsPrefix = Audio::Wwise::DefaultBanksPath; banksReferenced.emplace_back(soundsPrefix + bankNameAttribute->value()); @@ -496,7 +496,7 @@ namespace AudioControlBuilder pathDependencies.emplace(relativeBankPath, AssetBuilderSDK::ProductPathDependencyType::ProductFile); } - // For each bank figure out what events are included in the bank, then run through every event referenced in the file and + // For each bank figure out what events are included in the bank, then run through every event referenced in the file and // make sure it is in the list gathered from the banks. const auto triggersNode = node->first_node(Audio::ATLXmlTags::TriggersNodeTag); if (!triggersNode) @@ -520,7 +520,7 @@ namespace AudioControlBuilder AZStd::set wwiseEventsInReferencedBanks; - // Load all bankdeps files for all banks referenced and aggregate the list of events in those files. + // Load all bankdeps files for all banks referenced and aggregate the list of events in those files. for (const AZStd::string& relativeBankPath : banksReferenced) { // Create the full path to the bankdeps file from the bank file. diff --git a/Gems/AudioEngineWwise/Code/Source/Builder/WwiseBuilderWorker.cpp b/Gems/AudioEngineWwise/Code/Source/Builder/WwiseBuilderWorker.cpp index 3a1916edc3..22fa4cab7d 100644 --- a/Gems/AudioEngineWwise/Code/Source/Builder/WwiseBuilderWorker.cpp +++ b/Gems/AudioEngineWwise/Code/Source/Builder/WwiseBuilderWorker.cpp @@ -52,7 +52,7 @@ namespace WwiseBuilder { fileNames.push_back(dependenciesArray[dependencyIndex].GetString()); } - + // The dependency array is empty, which likely means it was modified by hand. However, every bank is dependent // on init.bnk (other than itself), so just force add it as a dependency here. and emit a warning. if (fileNames.size() == 0) @@ -93,7 +93,7 @@ namespace WwiseBuilder void WwiseBuilderWorker::Initialize() { - AZ::IO::Path configFile("@devassets@"); + AZ::IO::Path configFile("@projectroot@"); configFile /= Audio::Wwise::DefaultBanksPath; configFile /= Audio::Wwise::ConfigFile; @@ -180,7 +180,7 @@ namespace WwiseBuilder { AZ_TracePrintf(AssetBuilderSDK::InfoWindow, "Starting Job.\n"); AZ::IO::PathView fullPath(request.m_fullPath); - + if (m_isShuttingDown) { AZ_TracePrintf(AssetBuilderSDK::ErrorWindow, "Cancelled job %s because shutdown was requested.\n", request.m_fullPath.c_str()); @@ -204,7 +204,7 @@ namespace WwiseBuilder AZ::Outcome gatherProductDependenciesResponse = GatherProductDependencies(request.m_fullPath, request.m_sourceFile, dependencyPaths); if (!gatherProductDependenciesResponse.IsSuccess()) { - AZ_Error(WwiseBuilderWindowName, false, "Dependency gathering for %s failed. %s", + AZ_Error(WwiseBuilderWindowName, false, "Dependency gathering for %s failed. %s", request.m_fullPath.c_str(), gatherProductDependenciesResponse.GetError().c_str()); } else diff --git a/Gems/AudioEngineWwise/Code/Tests/AudioEngineWwiseBuilderTest.cpp b/Gems/AudioEngineWwise/Code/Tests/AudioEngineWwiseBuilderTest.cpp index 2387588f31..e65dbcce9f 100644 --- a/Gems/AudioEngineWwise/Code/Tests/AudioEngineWwiseBuilderTest.cpp +++ b/Gems/AudioEngineWwise/Code/Tests/AudioEngineWwiseBuilderTest.cpp @@ -28,7 +28,7 @@ protected: { m_app.Start(AZ::ComponentApplication::Descriptor()); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); @@ -39,7 +39,7 @@ protected: assetRoot /= "Cache"; AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", assetRoot.c_str()); - AZ::IO::FileIOBase::GetInstance()->SetAlias("@assets@", assetRoot.c_str()); + AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", assetRoot.c_str()); } void TearDown() override @@ -158,7 +158,7 @@ TEST_F(WwiseBuilderTests, WwiseBuilder_InitBank_NoMetadata_NoDependencies) TEST_F(WwiseBuilderTests, WwiseBuilder_ContentBank_NoMetadata_NoDependencies) { - // Should generate a warning after trying to find metadata for the given bank, when the bank is not the init bank. + // Should generate a warning after trying to find metadata for the given bank, when the bank is not the init bank. // Warning should be about not being able to generate full dependency information without the metadata file. TestSuccessCaseNoDependencies("test_doesNotExist.bnk", true); } @@ -180,15 +180,15 @@ TEST_F(WwiseBuilderTests, WwiseBuilder_ContentBank_MultipleDependencies) TEST_F(WwiseBuilderTests, WwiseBuilder_ContentBank_DependencyArrayNonexistent_NoDependencies) { - // Should generate a warning when trying to get dependency info from metadata file, but the dependency field does - // not an empty array. Warning should be describing that a dependency on the init bank was added by default, but + // Should generate a warning when trying to get dependency info from metadata file, but the dependency field does + // not an empty array. Warning should be describing that a dependency on the init bank was added by default, but // the full dependency list could not be generated. TestSuccessCaseNoDependencies("test_bank7.bnk", true); } TEST_F(WwiseBuilderTests, WwiseBuilder_ContentBank_NoElementsInDependencyArray_NoDependencies) { - // Should generate a warning when trying to get dependency info from metadata file, but the dependency field is + // Should generate a warning when trying to get dependency info from metadata file, but the dependency field is // an empty array. Warning should be describing that a dependency on the init bank was added by default, but the // full dependency list could not be generated. TestSuccessCaseNoDependencies("test_bank8.bnk", true); @@ -196,8 +196,8 @@ TEST_F(WwiseBuilderTests, WwiseBuilder_ContentBank_NoElementsInDependencyArray_N TEST_F(WwiseBuilderTests, WwiseBuilder_ContentBank_MissingInitBankDependency_MultipleDependencies) { - // Should generate a warning when trying to get dependency info from metadata file, but the dependency info in the - // metadata doesn't include the init bank. Warning should be describing that a dependency on the init bank was + // Should generate a warning when trying to get dependency info from metadata file, but the dependency info in the + // metadata doesn't include the init bank. Warning should be describing that a dependency on the init bank was // added by default. AZStd::vector expectedPaths = { "Sounds/wwise/init.bnk", diff --git a/Gems/AudioEngineWwise/Code/Tests/AudioEngineWwiseTest.cpp b/Gems/AudioEngineWwise/Code/Tests/AudioEngineWwiseTest.cpp index 3724069045..4ee816b048 100644 --- a/Gems/AudioEngineWwise/Code/Tests/AudioEngineWwiseTest.cpp +++ b/Gems/AudioEngineWwise/Code/Tests/AudioEngineWwiseTest.cpp @@ -231,7 +231,7 @@ namespace UnitTest m_app.Start(AZ::ComponentApplication::Descriptor()); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); @@ -253,10 +253,10 @@ namespace UnitTest AZ_TEST_ASSERT(serializeContext != nullptr); Audio::Wwise::ConfigurationSettings::Reflect(serializeContext); - // Set the @assets@ alias to the path where *this* cpp file lives. + // Set the @products@ alias to the path where *this* cpp file lives. AZStd::string rootFolder(AZ::Test::GetCurrentExecutablePath()); AZ::StringFunc::Path::Join(rootFolder.c_str(), "Test.Assets/Gems/AudioEngineWwise", rootFolder); - m_fileIO->SetAlias("@assets@", rootFolder.c_str()); + m_fileIO->SetAlias("@products@", rootFolder.c_str()); // So we don't have to compute it in each test... AZStd::string defaultBanksPath(Audio::Wwise::DefaultBanksPath); @@ -303,26 +303,12 @@ namespace UnitTest m_mapEntry.m_bankSubPath = "soundbanks"; config.m_platformMappings.push_back(m_mapEntry); - // Unfortunately we are writing to the config file that is simulated to be in the @assets@ subfolder - // This will cause an issue during save. Since 'm_configFilePath' is an absolute path, we need to - // reset the @assets@ alias to a meaningful assets path that does not contain any root of the m_configFilePath - // in order to write to the config file and proceed - //AZStd::string rootFolder(AZ::Test::GetCurrentExecutablePath()); - //AZ::IO::Path tempAssetPath(rootFolder); - //tempAssetPath /= "Cache"; - - //AZStd::string previousAlias = m_fileIO->GetAlias("@assets@"); - //m_fileIO->SetAlias("@assets@", tempAssetPath.c_str()); - config.Save(m_configFilePath); - //m_fileIO->SetAlias("@assets@", previousAlias.c_str()); m_wwiseImpl.SetBankPaths(); - //m_fileIO->SetAlias("@assets@", tempAssetPath.c_str()); m_fileIO->Remove(m_configFilePath.c_str()); - //m_fileIO->SetAlias("@assets@", previousAlias.c_str()); EXPECT_STREQ(m_wwiseImpl.m_soundbankFolder.c_str(), "sounds/wwise/soundbanks/"); } diff --git a/Gems/AudioSystem/Code/Source/Engine/ATLComponents.cpp b/Gems/AudioSystem/Code/Source/Engine/ATLComponents.cpp index 996a2a80b6..aa93a2bc12 100644 --- a/Gems/AudioSystem/Code/Source/Engine/ATLComponents.cpp +++ b/Gems/AudioSystem/Code/Source/Engine/ATLComponents.cpp @@ -977,7 +977,7 @@ namespace Audio , m_rPreloadRequests(rPreloadRequests) , m_nTriggerImplIDCounter(AUDIO_TRIGGER_IMPL_ID_NUM_RESERVED) , m_rFileCacheMgr(rFileCacheMgr) - , m_rootPath("@assets@") + , m_rootPath("@products@") #if !defined(AUDIO_RELEASE) , m_pDebugNameStore(nullptr) #endif // !AUDIO_RELEASE diff --git a/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp b/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp index 0c697f12b6..21ec1a4603 100644 --- a/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp +++ b/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp @@ -292,7 +292,7 @@ namespace Blast void BlastSystemComponent::SaveConfiguration() { - auto assetRoot = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@"); + auto assetRoot = AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@"); if (!assetRoot) { @@ -309,7 +309,7 @@ namespace Blast void BlastSystemComponent::CheckoutConfiguration() { - const auto assetRoot = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@"); + const auto assetRoot = AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@"); AZStd::string fullPath; AzFramework::StringFunc::Path::Join(assetRoot, DefaultConfigurationPath, fullPath); diff --git a/Gems/CertificateManager/Code/Source/DataSource/FileDataSource.cpp b/Gems/CertificateManager/Code/Source/DataSource/FileDataSource.cpp index 21b0b28c47..85c9c696a2 100644 --- a/Gems/CertificateManager/Code/Source/DataSource/FileDataSource.cpp +++ b/Gems/CertificateManager/Code/Source/DataSource/FileDataSource.cpp @@ -16,7 +16,7 @@ namespace CertificateManager { static bool ReadFileIntoString(const char* filename, AZStd::vector& outBuffer) { - AZStd::string certificatePath = "@assets@/certificates/"; + AZStd::string certificatePath = "@products@/certificates/"; certificatePath.append(filename); AZ::IO::FileIOBase* fileBase = AZ::IO::FileIOBase::GetInstance(); @@ -58,7 +58,7 @@ namespace CertificateManager return true; } - FileDataSource::FileDataSource() + FileDataSource::FileDataSource() : m_privateKeyPEM(nullptr) , m_certificatePEM(nullptr) , m_certificateAuthorityCertPEM(nullptr) @@ -73,13 +73,13 @@ namespace CertificateManager azfree(m_privateKeyPEM); azfree(m_certificatePEM); azfree(m_certificateAuthorityCertPEM); - } + } void FileDataSource::ConfigureDataSource(const char* keyPath, const char* certPath, const char* caPath) { ConfigurePrivateKey(keyPath); ConfigureCertificate(certPath); - ConfigureCertificateAuthority(caPath); + ConfigureCertificateAuthority(caPath); } void FileDataSource::ConfigurePrivateKey(const char* path) @@ -107,7 +107,7 @@ namespace CertificateManager if (path != nullptr) { LoadGenericFile(path,m_certificatePEM); - } + } } void FileDataSource::ConfigureCertificateAuthority(const char* path) @@ -133,7 +133,7 @@ namespace CertificateManager { return m_certificateAuthorityCertPEM; } - + bool FileDataSource::HasPublicKey() const { return m_certificatePEM != nullptr; @@ -143,7 +143,7 @@ namespace CertificateManager { return m_certificatePEM; } - + bool FileDataSource::HasPrivateKey() const { return m_privateKeyPEM != nullptr; diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/EMotionFXManager.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/EMotionFXManager.cpp index 300543c896..d5fa3867e0 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/EMotionFXManager.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/EMotionFXManager.cpp @@ -50,7 +50,7 @@ namespace EMotionFX // Create EMotion FX allocators Allocators::Create(); - + // create the new object gEMFX = AZ::Environment::CreateVariable(kEMotionFXInstanceVarName); gEMFX.Set(EMotionFXManager::Create()); @@ -166,11 +166,11 @@ namespace EMotionFX delete m_debugDraw; m_debugDraw = nullptr; - + m_eventManager->Destroy(); m_eventManager = nullptr; - + // delete the thread datas for (uint32 i = 0; i < m_threadDatas.size(); ++i) { @@ -341,7 +341,7 @@ namespace EMotionFX void EMotionFXManager::InitAssetFolderPaths() { // Initialize the asset source folder path. - const char* assetSourcePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@"); + const char* assetSourcePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@"); if (assetSourcePath) { m_assetSourceFolder = assetSourcePath; @@ -361,12 +361,12 @@ namespace EMotionFX } else { - AZ_Warning("EMotionFX", false, "Failed to set asset source path for alias '@devassets@'."); + AZ_Warning("EMotionFX", false, "Failed to set asset source path for alias '@projectroot@'."); } // Initialize the asset cache folder path. - const char* assetCachePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@assets@"); + const char* assetCachePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@products@"); if (assetCachePath) { m_assetCacheFolder = assetCachePath; @@ -386,7 +386,7 @@ namespace EMotionFX } else { - AZ_Warning("EMotionFX", false, "Failed to set asset cache path for alias '@assets@'."); + AZ_Warning("EMotionFX", false, "Failed to set asset cache path for alias '@products@'."); } } diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/FileManager.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/FileManager.cpp index 129d005f80..2d65a228b7 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/FileManager.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/FileManager.cpp @@ -72,13 +72,13 @@ namespace EMStudio { AZStd::string filename; - AZStd::string assetCachePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@assets@"); + AZStd::string assetCachePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@products@"); AzFramework::StringFunc::AssetDatabasePath::Normalize(assetCachePath); AZStd::string relativePath; EBUS_EVENT_RESULT(relativePath, AZ::Data::AssetCatalogRequestBus, GetAssetPathById, assetId); AzFramework::StringFunc::AssetDatabasePath::Join(assetCachePath.c_str(), relativePath.c_str(), filename); - + return filename; } @@ -243,7 +243,7 @@ namespace EMStudio void FileManager::SourceFileChanged(AZStd::string relativePath, AZStd::string scanFolder, [[maybe_unused]] AZ::TypeId sourceTypeId) { AZStd::string filename; - AZStd::string assetSourcePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@"); + AZStd::string assetSourcePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@projectroot@"); AzFramework::StringFunc::AssetDatabasePath::Normalize(assetSourcePath); AzFramework::StringFunc::AssetDatabasePath::Join(assetSourcePath.c_str(), relativePath.c_str(), filename); @@ -373,7 +373,7 @@ namespace EMStudio const ProductAssetBrowserEntry* product = azrtti_cast(assetBrowserEntry); filename.clear(); - AZStd::string cachePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@assets@"); + AZStd::string cachePath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@products@"); AzFramework::StringFunc::AssetDatabasePath::Normalize(cachePath); AzFramework::StringFunc::AssetDatabasePath::Join(cachePath.c_str(), product->GetRelativePath().c_str(), filename); @@ -395,7 +395,7 @@ namespace EMStudio { return AZStd::string(); } - + return filenames[0]; } @@ -435,12 +435,12 @@ namespace EMStudio AZStd::string result; if (EMStudio::GetCommandManager()->ExecuteCommand(command, result)) { - GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS, + GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS, "Actor successfully saved"); } else { - GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR, + GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR, AZStd::string::format("Actor failed to save

%s", result.c_str()).c_str()); } } @@ -574,12 +574,12 @@ namespace EMStudio AZStd::string result; if (GetCommandManager()->ExecuteCommand(command, result) == false) { - GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR, + GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR, AZStd::string::format("MotionSet failed to save

%s", result.c_str()).c_str()); } else { - GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS, + GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS, "MotionSet successfully saved"); } } @@ -608,7 +608,7 @@ namespace EMStudio } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - + AZStd::string FileManager::LoadAnimGraphFileDialog([[maybe_unused]] QWidget* parent) { GetManager()->SetAvoidRendering(true); @@ -618,7 +618,7 @@ namespace EMStudio { return AZStd::string(); } - + return filenames[0]; } 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 06088790d9..002634ea90 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp @@ -378,7 +378,7 @@ namespace EMStudio // reset action m_resetAction = menu->addAction(tr("&Reset"), this, &MainWindow::OnReset, QKeySequence::New); m_resetAction->setObjectName("EMFX.MainWindow.ResetAction"); - + // save all m_saveAllAction = menu->addAction(tr("Save All..."), this, &MainWindow::OnSaveAll, QKeySequence::Save); m_saveAllAction->setObjectName("EMFX.MainWindow.SaveAllAction"); @@ -467,7 +467,7 @@ namespace EMStudio menu->addAction("Documentation", this, [] { QDesktopServices::openUrl(QUrl("https://o3de.org/docs/")); - }); + }); menu->addAction("Forums", this, [] { @@ -491,7 +491,7 @@ namespace EMStudio // load preferences PluginOptionsNotificationsBus::Router::BusRouterConnect(); - LoadPreferences(); + LoadPreferences(); m_autosaveTimer->setInterval(m_options.GetAutoSaveInterval() * 60 * 1000); // Create the dirty file manager and register the workspace callback. @@ -1072,7 +1072,7 @@ namespace EMStudio // get only the version number of EMotion FX AZStd::string emfxVersionString = EMotionFX::GetEMotionFX().GetVersionString(); AzFramework::StringFunc::Replace(emfxVersionString, "EMotion FX ", "", true /* case sensitive */); - + // set the window title // only set the EMotion FX version if the filename is empty AZStd::string windowTitle; @@ -1359,7 +1359,7 @@ namespace EMStudio void MainWindow::LoadCharacter(const AZ::Data::AssetId& actorAssetId, const AZ::Data::AssetId& animgraphId, const AZ::Data::AssetId& motionSetId) { m_characterFiles.clear(); - AZStd::string cachePath = gEnv->pFileIO->GetAlias("@assets@"); + AZStd::string cachePath = gEnv->pFileIO->GetAlias("@products@"); AZStd::string filename; AzFramework::StringFunc::AssetDatabasePath::Normalize(cachePath); @@ -1543,12 +1543,12 @@ namespace EMStudio AZStd::string result; if (EMStudio::GetCommandManager()->ExecuteCommand(command, result)) { - GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS, + GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS, "Workspace successfully saved"); } else { - GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR, + GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR, AZStd::string::format("Workspace failed to save

%s", result.c_str()).c_str()); } } @@ -1575,12 +1575,12 @@ namespace EMStudio AZStd::string result; if (EMStudio::GetCommandManager()->ExecuteCommand(command, result)) { - GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS, + GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS, "Workspace successfully saved"); } else { - GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR, + GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR, AZStd::string::format("Workspace failed to save

%s", result.c_str()).c_str()); } } @@ -1644,7 +1644,7 @@ namespace EMStudio Workspace* workspace = GetManager()->GetWorkspace(); workspace->SetDirtyFlag(true); - } + } void MainWindow::OnReset() { @@ -2312,7 +2312,7 @@ namespace EMStudio void MainWindow::Activate(const AZ::Data::AssetId& actorAssetId, const EMotionFX::AnimGraph* animGraph, const EMotionFX::MotionSet* motionSet) { - AZStd::string cachePath = gEnv->pFileIO->GetAlias("@assets@"); + AZStd::string cachePath = gEnv->pFileIO->GetAlias("@products@"); AZStd::string filename; AzFramework::StringFunc::AssetDatabasePath::Normalize(cachePath); @@ -2776,17 +2776,17 @@ namespace EMStudio AZStd::string result; if (GetCommandManager()->ExecuteCommandGroup(commandGroup, result, false)) { - GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS, + GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_SUCCESS, "Autosave completed"); } else { - GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR, + GetNotificationWindowManager()->CreateNotificationWindow(NotificationWindow::TYPE_ERROR, AZStd::string::format("Autosave failed

%s", result.c_str()).c_str()); } } - + void MainWindow::moveEvent(QMoveEvent* event) { MCORE_UNUSED(event); diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/Workspace.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/Workspace.cpp index 4cdf645b16..ea7c92b742 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/Workspace.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/Workspace.cpp @@ -428,7 +428,7 @@ namespace EMStudio continue; } - AzFramework::StringFunc::Replace(commands[i], "@assets@/", assetCacheFolder.c_str(), true /* case sensitive */); + AzFramework::StringFunc::Replace(commands[i], "@products@/", assetCacheFolder.c_str(), true /* case sensitive */); // add the command to the command group commandGroup->AddCommandString(commands[i]); diff --git a/Gems/EMotionFX/Code/Source/Integration/Assets/AnimGraphAsset.cpp b/Gems/EMotionFX/Code/Source/Integration/Assets/AnimGraphAsset.cpp index 3e459d31d6..3593f58ff2 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Assets/AnimGraphAsset.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Assets/AnimGraphAsset.cpp @@ -6,6 +6,8 @@ * */ +#include + #include #include #include @@ -66,14 +68,10 @@ namespace EMotionFX // through this method. Once EMotionFX is integrated to the asset system this can go away. AZStd::string assetFilename; EBUS_EVENT_RESULT(assetFilename, AZ::Data::AssetCatalogRequestBus, GetAssetPathById, asset.GetId()); - const char* devAssetsPath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@"); - if (devAssetsPath) + AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath(); + if (!projectPath.empty()) { - AZStd::string assetSourcePath = devAssetsPath; - - AzFramework::StringFunc::AssetDatabasePath::Normalize(assetSourcePath); - AZStd::string filename; - AzFramework::StringFunc::AssetDatabasePath::Join(assetSourcePath.c_str(), assetFilename.c_str(), filename); + AZ::IO::FixedMaxPathString filename{ (projectPath / assetFilename).LexicallyNormal().FixedMaxPathStringAsPosix() }; assetData->m_emfxAnimGraph->SetFileName(filename.c_str()); } @@ -81,7 +79,7 @@ namespace EMotionFX { if (GetEMotionFX().GetIsInEditorMode()) { - AZ_Warning("EMotionFX", false, "Failed to retrieve asset source path with alias '@devassets@'. Cannot set absolute filename for '%s'", assetFilename.c_str()); + AZ_Warning("EMotionFX", false, "Failed to retrieve project root path . Cannot set absolute filename for '%s'", assetFilename.c_str()); } assetData->m_emfxAnimGraph->SetFileName(assetFilename.c_str()); } diff --git a/Gems/EMotionFX/Code/Source/Integration/Assets/MotionSetAsset.cpp b/Gems/EMotionFX/Code/Source/Integration/Assets/MotionSetAsset.cpp index 5ca9a34e72..280cedd06a 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Assets/MotionSetAsset.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Assets/MotionSetAsset.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -46,7 +47,7 @@ namespace EMotionFX const char* motionFile = entry->GetFilename(); AZ::Data::AssetId motionAssetId; EBUS_EVENT_RESULT(motionAssetId, AZ::Data::AssetCatalogRequestBus, GetAssetIdByPath, motionFile, azrtti_typeid(), false); - + // if it failed to find it, it might be still compiling - try forcing an immediate compile: if (!motionAssetId.IsValid()) { @@ -149,14 +150,11 @@ namespace EMotionFX // through this method. Once EMotionFX is integrated to the asset system this can go away. AZStd::string assetFilename; EBUS_EVENT_RESULT(assetFilename, AZ::Data::AssetCatalogRequestBus, GetAssetPathById, asset.GetId()); - const char* devAssetsPath = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@"); - if (devAssetsPath) - { - AZStd::string assetSourcePath = devAssetsPath; - AZ::StringFunc::AssetDatabasePath::Normalize(assetSourcePath); - AZStd::string filename; - AZ::StringFunc::AssetDatabasePath::Join(assetSourcePath.c_str(), assetFilename.c_str(), filename); + AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath(); + if (!projectPath.empty()) + { + AZ::IO::FixedMaxPathString filename{ (projectPath / assetFilename).LexicallyNormal().FixedMaxPathStringAsPosix() }; assetData->m_emfxMotionSet->SetFilename(filename.c_str()); } @@ -164,11 +162,11 @@ namespace EMotionFX { if (GetEMotionFX().GetIsInEditorMode()) { - AZ_Warning("EMotionFX", false, "Failed to retrieve asset source path with alias '@devassets@'. Cannot set absolute filename for '%s'", assetFilename.c_str()); + AZ_Warning("EMotionFX", false, "Failed to retrieve project root path . Cannot set absolute filename for '%s'", assetFilename.c_str()); } assetData->m_emfxMotionSet->SetFilename(assetFilename.c_str()); } - + // now load them in: const EMotionFX::MotionSet::MotionEntries& motionEntries = assetData->m_emfxMotionSet->GetMotionEntries(); // Get the motions in the motion set. Escalate them to the top of the build queue first so that they can be done in parallel. @@ -179,7 +177,7 @@ namespace EMotionFX const char* motionFilename = motionEntry->GetFilename(); AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, motionFilename); } - + // now that they're all escalated, the asset processor will be processing them across all threads, and we can request them one by one: for (const auto& item : motionEntries) { diff --git a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp index 0f87c488b9..08e99f97d0 100644 --- a/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/System/SystemComponent.cpp @@ -487,9 +487,9 @@ namespace EMotionFX return; } - SetMediaRoot("@assets@"); - // \todo Right now we're pointing at the @devassets@ location (source) and working from there, because .actor and .motion (motion) aren't yet processed through - // the scene pipeline. Once they are, we'll need to update various segments of the Tool to always read from the @assets@ cache, but write to the @devassets@ data/metadata. + SetMediaRoot("@products@"); + // \todo Right now we're pointing at the @projectroot@ location (source) and working from there, because .actor and .motion (motion) aren't yet processed through + // the scene pipeline. Once they are, we'll need to update various segments of the Tool to always read from the @products@ cache, but write to the @projectroot@ data/metadata. EMotionFX::GetEMotionFX().InitAssetFolderPaths(); // Register EMotionFX event handler diff --git a/Gems/EMotionFX/Code/Tests/Bugs/CanDeleteMotionSetWhenSameMotionInTwoMotionSets.cpp b/Gems/EMotionFX/Code/Tests/Bugs/CanDeleteMotionSetWhenSameMotionInTwoMotionSets.cpp index 25cd840cda..44453ed70f 100644 --- a/Gems/EMotionFX/Code/Tests/Bugs/CanDeleteMotionSetWhenSameMotionInTwoMotionSets.cpp +++ b/Gems/EMotionFX/Code/Tests/Bugs/CanDeleteMotionSetWhenSameMotionInTwoMotionSets.cpp @@ -25,11 +25,11 @@ namespace EMotionFX ExecuteCommands({ R"str(CreateMotionSet -name MotionSet0)str", R"str(CreateMotionSet -name MotionSet1)str", - R"str(MotionSetAddMotion -motionSetID 0 -motionFilenamesAndIds @devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion;rin_idle)str", - R"str(MotionSetAddMotion -motionSetID 1 -motionFilenamesAndIds @devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion;rin_idle)str", + R"str(MotionSetAddMotion -motionSetID 0 -motionFilenamesAndIds @engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion;rin_idle)str", + R"str(MotionSetAddMotion -motionSetID 1 -motionFilenamesAndIds @engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion;rin_idle)str", R"str(MotionSetRemoveMotion -motionSetID 0 -motionIds rin_idle)str", R"str(RemoveMotionSet -motionSetID 0)str", - R"str(RemoveMotion -filename @devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion)str", + R"str(RemoveMotion -filename @engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion)str", }); EMStudio::MotionSetsWindowPlugin* motionSetsWindowPlugin = static_cast(EMStudio::GetPluginManager()->FindActivePlugin(EMStudio::MotionSetsWindowPlugin::CLASS_ID)); diff --git a/Gems/EMotionFX/Code/Tests/CommandRemoveMotionTests.cpp b/Gems/EMotionFX/Code/Tests/CommandRemoveMotionTests.cpp index ce0b586bfe..e4e58fa01d 100644 --- a/Gems/EMotionFX/Code/Tests/CommandRemoveMotionTests.cpp +++ b/Gems/EMotionFX/Code/Tests/CommandRemoveMotionTests.cpp @@ -33,7 +33,7 @@ namespace EMotionFX ASSERT_TRUE(motionSet) << "Motion set with id 0 does not exist"; motionSetsWindowPlugin->SetSelectedSet(motionSet); - const std::string filename = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion"; + const std::string filename = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion"; ExecuteCommands({ "ImportMotion -filename " + filename, "MotionSetAddMotion -motionSetID 0 -motionFilenamesAndIds " + filename + ";rin_idle", diff --git a/Gems/EMotionFX/Code/Tests/EMotionFXBuilderTests.cpp b/Gems/EMotionFX/Code/Tests/EMotionFXBuilderTests.cpp index 0155b38da2..7b9f23f094 100644 --- a/Gems/EMotionFX/Code/Tests/EMotionFXBuilderTests.cpp +++ b/Gems/EMotionFX/Code/Tests/EMotionFXBuilderTests.cpp @@ -55,7 +55,7 @@ namespace EMotionFX // By using this mock catalog, we can pretend to load the specific referenced assets without actually loading anything. UnitTest::MockLoadAssetCatalogAndHandler testAssetCatalog({ referencedAnimGraph, referencedMotionSet }); - const AZStd::string fileName = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/AnimGraphExample.animgraph"; + const AZStd::string fileName = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/AnimGraphExample.animgraph"; AZStd::vector productDependencies; EMotionFXBuilder::AnimGraphBuilderWorker builderWorker; @@ -68,7 +68,7 @@ namespace EMotionFX TEST_F(EMotionFXBuilderTests, TestAnimGraphAsset_NoDependency_OutputNoProductDependencies) { - const AZStd::string fileName = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/AnimGraphExampleNoDependency.animgraph"; + const AZStd::string fileName = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/AnimGraphExampleNoDependency.animgraph"; AZStd::vector productDependencies; EMotionFXBuilder::AnimGraphBuilderWorker builderWorker; @@ -78,7 +78,7 @@ namespace EMotionFX TEST_F(EMotionFXBuilderTests, TestAnimGraphAsset_InvalidFilePath_OutputNoProductDependencies) { - const AZStd::string fileName = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/InvalidPathExample.animgraph"; + const AZStd::string fileName = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/InvalidPathExample.animgraph"; AZStd::vector productDependencies; EMotionFXBuilder::AnimGraphBuilderWorker builderWorker; @@ -88,7 +88,7 @@ namespace EMotionFX TEST_F(EMotionFXBuilderTests, TestAnimGraphAsset_EmptyFile_OutputNoProductDependencies) { - const AZStd::string fileName = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/EmptyAnimGraphExample.animgraph"; + const AZStd::string fileName = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/EmptyAnimGraphExample.animgraph"; AZStd::vector productDependencies; EMotionFXBuilder::AnimGraphBuilderWorker builderWorker; @@ -100,7 +100,7 @@ namespace EMotionFX TEST_F(EMotionFXBuilderTests, TestMotionSetAsset_HasReferenceNode_OutputProductDependencies) { - const AZStd::string fileName = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/MotionSetExample.motionset"; + const AZStd::string fileName = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/MotionSetExample.motionset"; ProductPathDependencySet productDependencies; EMotionFXBuilder::MotionSetBuilderWorker builderWorker; @@ -112,7 +112,7 @@ namespace EMotionFX TEST_F(EMotionFXBuilderTests, TestMotionSetAsset_NoDependency_OutputNoProductDependencies) { - const AZStd::string fileName = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/MotionSetExampleNoDependency.motionset"; + const AZStd::string fileName = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/MotionSetExampleNoDependency.motionset"; ProductPathDependencySet productDependencies; EMotionFXBuilder::MotionSetBuilderWorker builderWorker; @@ -122,7 +122,7 @@ namespace EMotionFX TEST_F(EMotionFXBuilderTests, TestMotionSetAsset_InvalidFilePath_OutputNoProductDependencies) { - const AZStd::string fileName = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/InvalidPathExample.motionset"; + const AZStd::string fileName = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/InvalidPathExample.motionset"; ProductPathDependencySet productDependencies; EMotionFXBuilder::MotionSetBuilderWorker builderWorker; @@ -132,7 +132,7 @@ namespace EMotionFX TEST_F(EMotionFXBuilderTests, TestMotionSetAsset_EmptyFile_OutputNoProductDependencies) { - const AZStd::string fileName = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/EmptyMotionSetExample.motionset"; + const AZStd::string fileName = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/EmptyMotionSetExample.motionset"; ProductPathDependencySet productDependencies; EMotionFXBuilder::MotionSetBuilderWorker builderWorker; diff --git a/Gems/EMotionFX/Code/Tests/Editor/MotionSetLoadEscalation.cpp b/Gems/EMotionFX/Code/Tests/Editor/MotionSetLoadEscalation.cpp index b1650ce0c6..905c4a825b 100644 --- a/Gems/EMotionFX/Code/Tests/Editor/MotionSetLoadEscalation.cpp +++ b/Gems/EMotionFX/Code/Tests/Editor/MotionSetLoadEscalation.cpp @@ -124,7 +124,7 @@ namespace EMotionFX { using testing::_; - const AZStd::string fileName = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/MotionSetExample.motionset"; + const AZStd::string fileName = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/EMotionFXBuilderTestAssets/MotionSetExample.motionset"; MockAssetSystemRequests assetSystem; EXPECT_CALL(assetSystem, CompileAssetSync(_)) diff --git a/Gems/EMotionFX/Code/Tests/Game/SamplePerformanceTests.cpp b/Gems/EMotionFX/Code/Tests/Game/SamplePerformanceTests.cpp index ff7ead3800..36abf2b1d2 100644 --- a/Gems/EMotionFX/Code/Tests/Game/SamplePerformanceTests.cpp +++ b/Gems/EMotionFX/Code/Tests/Game/SamplePerformanceTests.cpp @@ -302,7 +302,7 @@ namespace EMotionFX GetEMotionFX().SetMediaRootFolder(assetFolder.c_str()); GetEMotionFX().InitAssetFolderPaths(); - const char* actorFilename = "@assets@\\animationsamples\\advanced_rinlocomotion\\actor\\rinactor.actor"; + const char* actorFilename = "@products@\\animationsamples\\advanced_rinlocomotion\\actor\\rinactor.actor"; Importer* importer = GetEMotionFX().GetImporter(); importer->SetLoggingEnabled(false); @@ -402,9 +402,9 @@ namespace EMotionFX // This path points to assets in the advance rin demo. // To test different assets, change the path here. - const char* actorFilename = "@assets@\\AnimationSamples\\Advanced_RinLocomotion\\Actor\\rinActor.actor"; - const char* motionSetFilename = "@assets@\\AnimationSamples\\Advanced_RinLocomotion\\AnimationEditorFiles\\Advanced_RinLocomotion.motionset"; - const char* animGraphFilename = "@assets@\\AnimationSamples\\Advanced_RinLocomotion\\AnimationEditorFiles\\Advanced_RinLocomotion.animgraph"; + const char* actorFilename = "@products@\\AnimationSamples\\Advanced_RinLocomotion\\Actor\\rinActor.actor"; + const char* motionSetFilename = "@products@\\AnimationSamples\\Advanced_RinLocomotion\\AnimationEditorFiles\\Advanced_RinLocomotion.motionset"; + const char* animGraphFilename = "@products@\\AnimationSamples\\Advanced_RinLocomotion\\AnimationEditorFiles\\Advanced_RinLocomotion.animgraph"; Importer* importer = GetEMotionFX().GetImporter(); importer->SetLoggingEnabled(false); @@ -714,9 +714,9 @@ namespace EMotionFX // This path points to assets in the advance rin demo. // To test different assets, change the path here. - const char* actorFilename = "@assets@\\AnimationSamples\\Advanced_RinLocomotion\\Actor\\rinActor.actor"; - const char* motionSetFilename = "@assets@\\AnimationSamples\\Advanced_RinLocomotion\\AnimationEditorFiles\\Advanced_RinLocomotion.motionset"; - const char* animGraphFilename = "@assets@\\AnimationSamples\\Advanced_RinLocomotion\\AnimationEditorFiles\\Advanced_RinLocomotion.animgraph"; + const char* actorFilename = "@products@\\AnimationSamples\\Advanced_RinLocomotion\\Actor\\rinActor.actor"; + const char* motionSetFilename = "@products@\\AnimationSamples\\Advanced_RinLocomotion\\AnimationEditorFiles\\Advanced_RinLocomotion.motionset"; + const char* animGraphFilename = "@products@\\AnimationSamples\\Advanced_RinLocomotion\\AnimationEditorFiles\\Advanced_RinLocomotion.animgraph"; Importer* importer = GetEMotionFX().GetImporter(); importer->SetLoggingEnabled(false); @@ -772,13 +772,13 @@ namespace EMotionFX TEST_F(PerformanceTestFixture, DISABLED_MotionSamplingPerformanceNonUniform) { // Make sure that the motion is set to use NonUniform sampling! Change this in the scene settings! Otherwise you get wrong results. - TestMotionSamplingPerformance("@assets@\\animationsamples\\advanced_rinlocomotion\\motions\\rin_idle.motion"); + TestMotionSamplingPerformance("@products@\\animationsamples\\advanced_rinlocomotion\\motions\\rin_idle.motion"); } TEST_F(PerformanceTestFixture, DISABLED_MotionSamplingPerformanceUniform) { // Make sure that the motion is set to use Uniform sampling! Change this in the scene settings! Otherwise you get wrong results. - TestMotionSamplingPerformance("@assets@\\animationsamples\\advanced_rinlocomotion\\motions\\rin_walk_kick_01.motion"); + TestMotionSamplingPerformance("@products@\\animationsamples\\advanced_rinlocomotion\\motions\\rin_walk_kick_01.motion"); } } // namespace EMotionFX diff --git a/Gems/EMotionFX/Code/Tests/Integration/CanAddActor.cpp b/Gems/EMotionFX/Code/Tests/Integration/CanAddActor.cpp index 9b18ca5862..31e1f75d29 100644 --- a/Gems/EMotionFX/Code/Tests/Integration/CanAddActor.cpp +++ b/Gems/EMotionFX/Code/Tests/Integration/CanAddActor.cpp @@ -33,7 +33,7 @@ namespace EMotionFX ASSERT_EQ(GetActorManager().GetNumActors(), 0); // Load an Actor - const char* actorCmd{ "ImportActor -filename @devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor" }; + const char* actorCmd{ "ImportActor -filename @engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor" }; { AZStd::string result; EXPECT_TRUE(CommandSystem::GetCommandManager()->ExecuteCommand(actorCmd, result)) << result.c_str(); diff --git a/Gems/EMotionFX/Code/Tests/Integration/PoseComparisonTests.cpp b/Gems/EMotionFX/Code/Tests/Integration/PoseComparisonTests.cpp index cccf744cfc..27692a90ff 100644 --- a/Gems/EMotionFX/Code/Tests/Integration/PoseComparisonTests.cpp +++ b/Gems/EMotionFX/Code/Tests/Integration/PoseComparisonTests.cpp @@ -297,16 +297,16 @@ namespace EMotionFX INSTANTIATE_TEST_CASE_P(Integ_TestPoses, INTEG_PoseComparisonFixture, ::testing::Values( PoseComparisonFixtureParams ( - "@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor", - "@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph", - "@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.motionset", - "@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.emfxrecording" + "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor", + "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph", + "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.motionset", + "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.emfxrecording" ), PoseComparisonFixtureParams ( - "@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.actor", - "@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.animgraph", - "@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.motionset", - "@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.emfxrecording" + "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.actor", + "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.animgraph", + "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.motionset", + "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Pendulum/pendulum.emfxrecording" ) ) ); @@ -314,10 +314,10 @@ namespace EMotionFX INSTANTIATE_TEST_CASE_P(Integ_TestPoseComparison, INTEG_TestPoseComparisonFixture, ::testing::Values( PoseComparisonFixtureParams ( - "@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor", - "@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph", - "@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.motionset", - "@assets@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.emfxrecording" + "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor", + "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph", + "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.motionset", + "@products@/Test.Assets/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.emfxrecording" ) ) ); diff --git a/Gems/EMotionFX/Code/Tests/ProvidesUI/AnimGraph/PreviewMotionFixture.cpp b/Gems/EMotionFX/Code/Tests/ProvidesUI/AnimGraph/PreviewMotionFixture.cpp index 287c34723f..16b223914e 100644 --- a/Gems/EMotionFX/Code/Tests/ProvidesUI/AnimGraph/PreviewMotionFixture.cpp +++ b/Gems/EMotionFX/Code/Tests/ProvidesUI/AnimGraph/PreviewMotionFixture.cpp @@ -30,12 +30,12 @@ namespace EMotionFX motionSetsWindowPlugin->SetSelectedSet(motionSet); ExecuteCommands({ - "ImportMotion -filename @devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion", - "MotionSetAddMotion -motionSetID 0 -motionFilenamesAndIds @devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion;rin_idle" + "ImportMotion -filename @engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion", + "MotionSetAddMotion -motionSetID 0 -motionFilenamesAndIds @engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion;rin_idle" }); char resolvedPath[AZ::IO::MaxPathLength]; - EXPECT_TRUE(AZ::IO::FileIOBase::GetInstance()->ResolvePath("@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion", resolvedPath, AZ_ARRAY_SIZE(resolvedPath))); + EXPECT_TRUE(AZ::IO::FileIOBase::GetInstance()->ResolvePath("@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion", resolvedPath, AZ_ARRAY_SIZE(resolvedPath))); m_motionFileName = resolvedPath; AzFramework::ApplicationRequests::Bus::Broadcast([](AzFramework::ApplicationRequests* requests, AZStd::string& path) { requests->NormalizePathKeepCase(path); }, m_motionFileName); m_motionName = "rin_idle"; diff --git a/Gems/EMotionFX/Code/Tests/ProvidesUI/Menus/FileMenu/CanReset.cpp b/Gems/EMotionFX/Code/Tests/ProvidesUI/Menus/FileMenu/CanReset.cpp index 1f9a78a413..d53ddcc924 100644 --- a/Gems/EMotionFX/Code/Tests/ProvidesUI/Menus/FileMenu/CanReset.cpp +++ b/Gems/EMotionFX/Code/Tests/ProvidesUI/Menus/FileMenu/CanReset.cpp @@ -44,7 +44,7 @@ namespace EMotionFX RecordProperty("test_case_id", "C16302179"); - const AZStd::string motionAsset("@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion"); + const AZStd::string motionAsset("@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion"); const AZStd::string createAnimGraphCmd("CreateAnimGraph"); const AZStd::string motionSetName("TestMotionSet"); const AZStd::string createMotionSetCmd("CreateMotionSet -motionSetID 42 -name " + motionSetName); diff --git a/Gems/EMotionFX/Code/Tests/ProvidesUI/Motions/CanAddMotions.cpp b/Gems/EMotionFX/Code/Tests/ProvidesUI/Motions/CanAddMotions.cpp index 82bfeba557..bb8368b17e 100644 --- a/Gems/EMotionFX/Code/Tests/ProvidesUI/Motions/CanAddMotions.cpp +++ b/Gems/EMotionFX/Code/Tests/ProvidesUI/Motions/CanAddMotions.cpp @@ -36,7 +36,7 @@ namespace EMotionFX RecordProperty("test_case_id", "C1559124"); const QString assetName = "rin_idle"; // Asset name to appear in table - const AZStd::string motionCmd = AZStd::string::format("ImportMotion -filename @devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion"); + const AZStd::string motionCmd = AZStd::string::format("ImportMotion -filename @engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion"); auto motionWindowPlugin = static_cast(EMStudio::GetPluginManager()->FindActivePlugin(EMStudio::MotionWindowPlugin::CLASS_ID)); ASSERT_TRUE(motionWindowPlugin) << "Could not find the Motion Window Plugin"; diff --git a/Gems/EMotionFX/Code/Tests/ProvidesUI/Motions/MotionPlaybacksTests.cpp b/Gems/EMotionFX/Code/Tests/ProvidesUI/Motions/MotionPlaybacksTests.cpp index 6804d351cf..14d27ed60f 100644 --- a/Gems/EMotionFX/Code/Tests/ProvidesUI/Motions/MotionPlaybacksTests.cpp +++ b/Gems/EMotionFX/Code/Tests/ProvidesUI/Motions/MotionPlaybacksTests.cpp @@ -38,7 +38,7 @@ namespace EMotionFX EXPECT_EQ(table->rowCount(), 1) << "Expected the table to have no rows yet"; // Create actor and actor instance. - const char* actorFilename = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor"; + const char* actorFilename = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.actor"; AZStd::unique_ptr m_actor = EMotionFX::GetImporter().LoadActor(actorFilename); EXPECT_TRUE(m_actor.get() != nullptr) << "Actor not loaded."; EMotionFX::ActorInstance* m_actorInstance = ActorInstance::Create(m_actor.get()); diff --git a/Gems/EMotionFX/Code/Tests/UI/CanAutoSaveFile.cpp b/Gems/EMotionFX/Code/Tests/UI/CanAutoSaveFile.cpp index 4eb44a54ab..bdbc50fe9c 100644 --- a/Gems/EMotionFX/Code/Tests/UI/CanAutoSaveFile.cpp +++ b/Gems/EMotionFX/Code/Tests/UI/CanAutoSaveFile.cpp @@ -26,7 +26,7 @@ namespace EMotionFX EMStudio::GetMainWindow()->ApplicationModeChanged("AnimGraph"); // Load Rin anim graph. - const char* rinGraph = "@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph"; + const char* rinGraph = "@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin.animgraph"; const AZStd::string rinGraphPath = ResolvePath(rinGraph); AZStd::string command = AZStd::string::format("LoadAnimGraph -filename \"%s\"", rinGraphPath.c_str()); AZStd::string result; diff --git a/Gems/EMotionFX/Code/Tests/UI/CanUseFileMenu.cpp b/Gems/EMotionFX/Code/Tests/UI/CanUseFileMenu.cpp index b24971bfde..73a0f1c865 100644 --- a/Gems/EMotionFX/Code/Tests/UI/CanUseFileMenu.cpp +++ b/Gems/EMotionFX/Code/Tests/UI/CanUseFileMenu.cpp @@ -551,7 +551,7 @@ namespace EMotionFX QString GetTestMotionFileName() const { - AZStd::string resolvedAssetPath = this->ResolvePath("@devroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion"); + AZStd::string resolvedAssetPath = this->ResolvePath("@engroot@/Gems/EMotionFX/Code/Tests/TestAssets/Rin/rin_idle.motion"); return QString::fromUtf8(resolvedAssetPath.data(), aznumeric_cast(resolvedAssetPath.size())); } diff --git a/Gems/EditorPythonBindings/Assets/release_notes.md b/Gems/EditorPythonBindings/Assets/release_notes.md index 4a4b5bc71f..59192e1fdc 100644 --- a/Gems/EditorPythonBindings/Assets/release_notes.md +++ b/Gems/EditorPythonBindings/Assets/release_notes.md @@ -59,7 +59,7 @@ The API: - ExecuteByString(string) – runs a string buffer in the Python VM; it returns no value - ExecuteByFilename(string) – loads a file off of the disk to execute in the Python VM; the call returns no value. The filename can contain an alias such as - ‘\@devroot\@’ to execute a project relative file inside the Editor + ‘\@projectroot\@’ to execute a project relative file inside the Editor #### New Console Commands diff --git a/Gems/EditorPythonBindings/Code/Source/PythonReflectionComponent.cpp b/Gems/EditorPythonBindings/Code/Source/PythonReflectionComponent.cpp index 4ca40a5bab..81476bdd7f 100644 --- a/Gems/EditorPythonBindings/Code/Source/PythonReflectionComponent.cpp +++ b/Gems/EditorPythonBindings/Code/Source/PythonReflectionComponent.cpp @@ -38,7 +38,7 @@ namespace EditorPythonBindings static constexpr const char* s_default = "default"; static constexpr const char* s_globals = "globals"; - // a structure for pybind11 to bind to hold constants, properties, and enums from the Behavior Context + // a structure for pybind11 to bind to hold constants, properties, and enums from the Behavior Context struct StaticPropertyHolder final { AZ_CLASS_ALLOCATOR(StaticPropertyHolder, AZ::SystemAllocator, 0); @@ -54,7 +54,7 @@ namespace EditorPythonBindings if (m_behaviorContext == nullptr) { return false; - } + } m_fullName = PyModule_GetName(scope.ptr()); @@ -199,12 +199,10 @@ namespace EditorPythonBindings } }); - RegisterAliasIfExists(pathsModule, "@devroot@", "devroot"); RegisterAliasIfExists(pathsModule, "@engroot@", "engroot"); - RegisterAliasIfExists(pathsModule, "@assets@", "assets"); - RegisterAliasIfExists(pathsModule, "@devassets@", "devassets"); + RegisterAliasIfExists(pathsModule, "@products@", "products"); + RegisterAliasIfExists(pathsModule, "@projectroot@", "projectroot"); RegisterAliasIfExists(pathsModule, "@log@", "log"); - RegisterAliasIfExists(pathsModule, "@root@", "root"); const char* executableFolder = nullptr; AZ::ComponentApplicationBus::BroadcastResult(executableFolder, &AZ::ComponentApplicationBus::Events::GetExecutableFolder); @@ -363,7 +361,7 @@ namespace EditorPythonBindings m_staticPropertyHolderMap.reset(); EditorPythonBindings::EditorPythonBindingsNotificationBus::Handler::BusDisconnect(); } - + void PythonReflectionComponent::OnImportModule(PyObject* module) { pybind11::module parentModule = pybind11::cast(module); diff --git a/Gems/EditorPythonBindings/Code/Source/PythonSystemComponent.cpp b/Gems/EditorPythonBindings/Code/Source/PythonSystemComponent.cpp index cecbf15c5a..876ef19803 100644 --- a/Gems/EditorPythonBindings/Code/Source/PythonSystemComponent.cpp +++ b/Gems/EditorPythonBindings/Code/Source/PythonSystemComponent.cpp @@ -524,7 +524,7 @@ namespace EditorPythonBindings { AZ::IO::Path newSourcePath = jsonSourcePathPointer; // Resolve any file aliases first - Do not use ResolvePath() as that assumes - // any relative path is underneath the @assets@ alias + // any relative path is underneath the @products@ alias if (auto fileIoBase = AZ::IO::FileIOBase::GetInstance(); fileIoBase != nullptr) { AZ::IO::FixedMaxPath replacedAliasPath; @@ -803,7 +803,7 @@ namespace EditorPythonBindings return Result::Error_InvalidFilename; } - // support the alias version of a script such as @devroot@/Editor/Scripts/select_story_anim_objects.py + // support the alias version of a script such as @engroot@/Editor/Scripts/select_story_anim_objects.py AZStd::string theFilename(filename); { char resolvedPath[AZ_MAX_PATH_LEN] = { 0 }; diff --git a/Gems/EditorPythonBindings/Code/Tests/PythonBindingLibTests.cpp b/Gems/EditorPythonBindings/Code/Tests/PythonBindingLibTests.cpp index 12d7d696d3..5aa4921287 100644 --- a/Gems/EditorPythonBindings/Code/Tests/PythonBindingLibTests.cpp +++ b/Gems/EditorPythonBindings/Code/Tests/PythonBindingLibTests.cpp @@ -268,7 +268,7 @@ print ('entityId invalid is ' + str(entityId.id)) { Skip = 0, ImportModule, - TestCallHit, + TestCallHit, TestTypeDoCall1 }; @@ -302,7 +302,7 @@ print ('entityId invalid is ' + str(entityId.id)) pybind11::exec(R"( import sys, os import azlmbr.paths - sys.path.append(os.path.join(azlmbr.paths.devroot,'Gems','EditorPythonBindings','Code','Tests')) + sys.path.append(os.path.join(azlmbr.paths.engroot,'Gems','EditorPythonBindings','Code','Tests')) from test_package import import_test as itest print('ImportModule') itest.test_call() @@ -401,8 +401,8 @@ print ('entityId invalid is ' + str(entityId.id)) pybind11::exec(R"( import sys, os import azlmbr.paths - sys.path.append(os.path.join(azlmbr.paths.devroot,'Gems','EditorPythonBindings','Code','Tests')) - sys.path.append(os.path.join(azlmbr.paths.devroot,'Gems','EditorPythonBindings','Code','Tests','test_package')) + sys.path.append(os.path.join(azlmbr.paths.engroot,'Gems','EditorPythonBindings','Code','Tests')) + sys.path.append(os.path.join(azlmbr.paths.engroot,'Gems','EditorPythonBindings','Code','Tests','test_package')) from test_package import import_many import_many.test_many_entity_id() diff --git a/Gems/EditorPythonBindings/Code/Tests/PythonReflectionComponentTests.cpp b/Gems/EditorPythonBindings/Code/Tests/PythonReflectionComponentTests.cpp index f68bef1c93..96619997bc 100644 --- a/Gems/EditorPythonBindings/Code/Tests/PythonReflectionComponentTests.cpp +++ b/Gems/EditorPythonBindings/Code/Tests/PythonReflectionComponentTests.cpp @@ -161,7 +161,7 @@ namespace UnitTest ->Method("accept_vector_of_floats", &PythonReflectionContainerSimpleTypes::AcceptVectorOfFloats, nullptr, "") ->Method("return_vector_of_doubles", &PythonReflectionContainerSimpleTypes::ReturnVectorOfDoubles, nullptr, "") ->Method("accept_vector_of_doubles", &PythonReflectionContainerSimpleTypes::AcceptVectorOfDoubles, nullptr, "") - ->Property("vector_of_s8", + ->Property("vector_of_s8", [](PythonReflectionContainerSimpleTypes* self) { return self->m_s8ValueValues.ReturnValues(); }, [](PythonReflectionContainerSimpleTypes* self, const AZStd::vector& values) { return self->m_s8ValueValues.AcceptValues(values); }) ->Property("vector_of_u8", @@ -792,7 +792,7 @@ namespace UnitTest theAsset = reflectAny.access_any_ref() if( reflectAny.compare_asset_ids(theAsset,testObject.theAsset) ): print ('MutateAssetId') - + )"); } catch ([[maybe_unused]] const std::exception& e) @@ -1429,7 +1429,6 @@ namespace UnitTest { Skip = 0, EngrootIs, - DevrootIs, pathResolvedTo, }; @@ -1442,10 +1441,6 @@ namespace UnitTest { return static_cast(LogTypes::EngrootIs); } - else if (AzFramework::StringFunc::StartsWith(message, "devroot is ")) - { - return static_cast(LogTypes::DevrootIs); - } else if (AzFramework::StringFunc::StartsWith(message, "path resolved to ")) { return static_cast(LogTypes::pathResolvedTo); @@ -1470,9 +1465,6 @@ namespace UnitTest if (len(azlmbr.paths.engroot) != 0): print ('engroot is {}'.format(azlmbr.paths.engroot)) - if (len(azlmbr.paths.devroot) != 0): - print ('devroot is {}'.format(azlmbr.paths.devroot)) - path = azlmbr.paths.resolve_path('@engroot@/engineassets/texturemsg/defaultsolids.mtl') if (path.find('@engroot@') == -1): print ('path resolved to {}'.format(path)) @@ -1487,7 +1479,6 @@ namespace UnitTest e.Deactivate(); EXPECT_EQ(m_testSink.m_evaluationMap[(int)LogTypes::EngrootIs], 1); - EXPECT_EQ(m_testSink.m_evaluationMap[(int)LogTypes::DevrootIs], 1); EXPECT_EQ(m_testSink.m_evaluationMap[(int)LogTypes::pathResolvedTo], 1); } } diff --git a/Gems/EditorPythonBindings/Code/Tests/PythonTestingUtility.h b/Gems/EditorPythonBindings/Code/Tests/PythonTestingUtility.h index a0109f8029..143863b4c8 100644 --- a/Gems/EditorPythonBindings/Code/Tests/PythonTestingUtility.h +++ b/Gems/EditorPythonBindings/Code/Tests/PythonTestingUtility.h @@ -81,7 +81,6 @@ namespace UnitTest } m_fileIOHelper = AZStd::make_unique(); - m_fileIOHelper->m_fileIO.SetAlias("@devroot@", m_engineRoot.c_str()); m_fileIOHelper->m_fileIO.SetAlias("@engroot@", m_engineRoot.c_str()); AzFramework::Application::Descriptor appDesc; diff --git a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLevelLoading.inl b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLevelLoading.inl index 38747553a9..7dbe516aa5 100644 --- a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLevelLoading.inl +++ b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLevelLoading.inl @@ -27,7 +27,7 @@ namespace GameStateSamples IConsole* iConsole = iSystem ? iSystem->GetIConsole() : nullptr; if (iConsole) { - iConsole->GetCVar("level_load_screen_uicanvas_path")->Set("@assets@/ui/canvases/defaultlevelloadingscreen.uicanvas"); + iConsole->GetCVar("level_load_screen_uicanvas_path")->Set("@products@/ui/canvases/defaultlevelloadingscreen.uicanvas"); iConsole->GetCVar("level_load_screen_sequence_to_auto_play")->Set("DefaultLevelLoadingAnimatedSequence"); } } diff --git a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLevelPaused.inl b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLevelPaused.inl index 63fea35224..4227e45fe9 100644 --- a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLevelPaused.inl +++ b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLevelPaused.inl @@ -182,7 +182,7 @@ namespace GameStateSamples //////////////////////////////////////////////////////////////////////////////////////////////// inline const char* GameStateLevelPaused::GetPauseMenuCanvasAssetPath() { - return "@assets@/ui/canvases/defaultpausemenuscreen.uicanvas"; + return "@products@/ui/canvases/defaultpausemenuscreen.uicanvas"; } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLevelRunning.inl b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLevelRunning.inl index f9ec19581c..a4af32feb8 100644 --- a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLevelRunning.inl +++ b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLevelRunning.inl @@ -206,6 +206,6 @@ namespace GameStateSamples //////////////////////////////////////////////////////////////////////////////////////////////// inline const char* GameStateLevelRunning::GetPauseButtonCanvasAssetPath() { - return "@assets@/ui/canvases/defaultpausebuttonfortouchscreens.uicanvas"; + return "@products@/ui/canvases/defaultpausebuttonfortouchscreens.uicanvas"; } } diff --git a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLocalUserLobby.inl b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLocalUserLobby.inl index dc658611b5..4a4fbac93a 100644 --- a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLocalUserLobby.inl +++ b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateLocalUserLobby.inl @@ -223,7 +223,7 @@ namespace GameStateSamples //////////////////////////////////////////////////////////////////////////////////////////////// inline const char* GameStateLocalUserLobby::GetSignedInUserOverlayCanvasAssetPath() { - return "@assets@/ui/canvases/defaultsignedinusersoverlay.uicanvas"; + return "@products@/ui/canvases/defaultsignedinusersoverlay.uicanvas"; } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -282,7 +282,7 @@ namespace GameStateSamples } // ...sort them by index and then go through to check whether they have been - // assigned a local user id. If so, auto-assign their local user id into the + // assigned a local user id. If so, auto-assign their local user id into the // first available local player slot (unless they've already been assigned). AZStd::sort(gamepadInputDevices.begin(), gamepadInputDevices.end(), [](const AzFramework::InputDevice* lhs, const AzFramework::InputDevice* rhs) diff --git a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateMainMenu.inl b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateMainMenu.inl index 41ee034844..98147756f4 100644 --- a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateMainMenu.inl +++ b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateMainMenu.inl @@ -257,7 +257,7 @@ namespace GameStateSamples //////////////////////////////////////////////////////////////////////////////////////////////// inline const char* GameStateMainMenu::GetMainMenuCanvasAssetPath() { - return "@assets@/ui/canvases/defaultmainmenuscreen.uicanvas"; + return "@products@/ui/canvases/defaultmainmenuscreen.uicanvas"; } diff --git a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateOptionsMenu.inl b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateOptionsMenu.inl index 64269d223f..4389f5f0b7 100644 --- a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateOptionsMenu.inl +++ b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStateOptionsMenu.inl @@ -215,7 +215,7 @@ namespace GameStateSamples //////////////////////////////////////////////////////////////////////////////////////////////// inline const char* GameStateOptionsMenu::GetOptionsMenuCanvasAssetPath() { - return "@assets@/ui/canvases/defaultoptionsmenuscreen.uicanvas"; + return "@products@/ui/canvases/defaultoptionsmenuscreen.uicanvas"; } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStatePrimaryUserSelection.inl b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStatePrimaryUserSelection.inl index bf50913ef9..42ad2290e1 100644 --- a/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStatePrimaryUserSelection.inl +++ b/Gems/GameStateSamples/Code/Include/GameStateSamples/GameStatePrimaryUserSelection.inl @@ -168,6 +168,6 @@ namespace GameStateSamples //////////////////////////////////////////////////////////////////////////////////////////////// inline const char* GameStatePrimaryUserSelection::GetPrimaryUserSelectionCanvasAssetPath() { - return "@assets@/ui/canvases/defaultprimaryuserselectionscreen.uicanvas"; + return "@products@/ui/canvases/defaultprimaryuserselectionscreen.uicanvas"; } } diff --git a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/StyleManager.cpp b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/StyleManager.cpp index 56f6e84332..0b4691ecf5 100644 --- a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/StyleManager.cpp +++ b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/StyleManager.cpp @@ -74,10 +74,10 @@ namespace m_paletteSwatches.push_back(QColor(0, 0, 0)); m_sourcePixmap = new QPixmap(16, 16); m_sourcePixmap->fill(Qt::transparent); - + QPainter painter(m_sourcePixmap); painter.setRenderHint(QPainter::RenderHint::Antialiasing); - + QPen pen; pen.setWidth(4); pen.setColor(QColor(0, 0, 0)); @@ -257,7 +257,7 @@ namespace GraphCanvas QBitmap mask = m_sourcePixmap->createMaskFromColor(m_paletteSwatches[i], Qt::MaskOutColor); painter.setClipRegion(QRegion(mask)); - QtDrawingUtils::FillArea(painter, drawRect, (*palettes[i%palettes.size()])); + QtDrawingUtils::FillArea(painter, drawRect, (*palettes[i%palettes.size()])); } return pixmap; @@ -317,7 +317,7 @@ namespace GraphCanvas void StyleManager::LoadStyleSheet() { - AZStd::string file = AZStd::string::format("@assets@/%s", m_assetPath.c_str()); + AZStd::string file = AZStd::string::format("@products@/%s", m_assetPath.c_str()); AZ::IO::FileIOBase* fileBase = AZ::IO::FileIOBase::GetInstance(); @@ -448,7 +448,7 @@ namespace GraphCanvas auto mapIter = m_dataPaletteMapping.find(dataType); if (mapIter == m_dataPaletteMapping.end()) - { + { return "ObjectDataColorPalette"; } else @@ -852,7 +852,7 @@ namespace GraphCanvas return icon; } - + void StyleManager::ClearStyles() { StyleManagerNotificationBus::Event(m_editorId, &StyleManagerNotifications::OnStylesUnloaded); diff --git a/Gems/InAppPurchases/Code/Source/Platform/Android/InAppPurchasesAndroid.cpp b/Gems/InAppPurchases/Code/Source/Platform/Android/InAppPurchasesAndroid.cpp index bd13e91dc6..d0d7160a73 100644 --- a/Gems/InAppPurchases/Code/Source/Platform/Android/InAppPurchasesAndroid.cpp +++ b/Gems/InAppPurchases/Code/Source/Platform/Android/InAppPurchasesAndroid.cpp @@ -58,7 +58,7 @@ namespace InAppPurchases } PurchasedProductDetailsAndroid* purchasedProductDetails = new PurchasedProductDetailsAndroid(); - + purchasedProductDetails->SetProductId(AZ::Android::JNI::ConvertJstringToString(static_cast(env->GetObjectField(jpurchasedProduct, fid[0])))); purchasedProductDetails->SetOrderId(AZ::Android::JNI::ConvertJstringToString(static_cast(env->GetObjectField(jpurchasedProduct, fid[1])))); purchasedProductDetails->SetPackageName(AZ::Android::JNI::ConvertJstringToString(static_cast(env->GetObjectField(jpurchasedProduct, fid[2])))); @@ -75,7 +75,7 @@ namespace InAppPurchases int numProducts = env->GetArrayLength(jproductDetails); InAppPurchasesInterface::GetInstance()->GetCache()->ClearCachedProductDetails(); - + const int NUM_FIELDS_PRODUCTS = 7; jfieldID fid[NUM_FIELDS_PRODUCTS]; jclass cls; @@ -224,7 +224,7 @@ namespace InAppPurchases AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle; AZ::u64 fileSize = 0; - if (!fileReader->Open("@assets@/product_ids.json", AZ::IO::OpenMode::ModeRead, fileHandle)) + if (!fileReader->Open("@products@/product_ids.json", AZ::IO::OpenMode::ModeRead, fileHandle)) { AZ_TracePrintf("LumberyardInAppBilling", "Unable to open file product_ids.json\n"); return; @@ -319,10 +319,10 @@ namespace InAppPurchases env->DeleteLocalRef(billingClass); } - + void InAppPurchasesAndroid::RestorePurchasedProducts() const { - + } void InAppPurchasesAndroid::ConsumePurchase(const AZStd::string& purchaseToken) const diff --git a/Gems/LmbrCentral/Code/Source/Builders/CopyDependencyBuilder/EmfxWorkspaceBuilderWorker/EmfxWorkspaceBuilderWorker.cpp b/Gems/LmbrCentral/Code/Source/Builders/CopyDependencyBuilder/EmfxWorkspaceBuilderWorker/EmfxWorkspaceBuilderWorker.cpp index 82c07f9f73..3dd7d5501e 100644 --- a/Gems/LmbrCentral/Code/Source/Builders/CopyDependencyBuilder/EmfxWorkspaceBuilderWorker/EmfxWorkspaceBuilderWorker.cpp +++ b/Gems/LmbrCentral/Code/Source/Builders/CopyDependencyBuilder/EmfxWorkspaceBuilderWorker/EmfxWorkspaceBuilderWorker.cpp @@ -63,13 +63,13 @@ namespace CopyDependencyBuilder charBuffer.back() = 0; /* File Contents of EMFX Workspace file looks like - startScript="ImportActor -filename \"@assets@/animationsamples/advanced_rinlocomotion/actor/rinactor.actor\"\nCreateActorInstance + startScript="ImportActor -filename \"@products@/animationsamples/advanced_rinlocomotion/actor/rinactor.actor\"\nCreateActorInstance -actorID %LASTRESULT% -xPos 0.000000 -yPos 0.020660 -zPos 0.000000 -xScale 1.000000 -yScale 1.000000 -zScale 1.000000 -rot 0.00000000, - 0.00000000,0.00000000,0.99997193\n LoadMotionSet -filename \"@assets@/AnimationSamples/Advanced_RinLocomotion/AnimationEditorFiles/Advanced_RinLocomotion.motionset\" - \nLoadAnimGraph -filename \"@assets@/AnimationSamples/Advanced_RinLocomotion/AnimationEditorFiles/Advanced_RinLocomotion.animgraph\" + 0.00000000,0.00000000,0.99997193\n LoadMotionSet -filename \"@products@/AnimationSamples/Advanced_RinLocomotion/AnimationEditorFiles/Advanced_RinLocomotion.motionset\" + \nLoadAnimGraph -filename \"@products@/AnimationSamples/Advanced_RinLocomotion/AnimationEditorFiles/Advanced_RinLocomotion.animgraph\" \nActivateAnimGraph -actorInstanceID %LASTRESULT3% -animGraphID %LASTRESULT1% -motionSetID %LASTRESULT2% -visualizeScale 1.000000\n" */ - AZStd::regex pathRegex(R"(\s+-filename\s+\\\"(?:@assets@\/)?(\S+)\\\")"); + AZStd::regex pathRegex(R"(\s+-filename\s+\\\"(?:@products@\/)?(\S+)\\\")"); AZStd::smatch matches; AZStd::string::const_iterator searchStart = charBuffer.begin(); while (AZStd::regex_search(searchStart, matches, pathRegex)) diff --git a/Gems/LmbrCentral/Code/Source/Builders/LevelBuilder/LevelBuilderWorker.cpp b/Gems/LmbrCentral/Code/Source/Builders/LevelBuilder/LevelBuilderWorker.cpp index 631bc41358..00e9eaf0fe 100644 --- a/Gems/LmbrCentral/Code/Source/Builders/LevelBuilder/LevelBuilderWorker.cpp +++ b/Gems/LmbrCentral/Code/Source/Builders/LevelBuilder/LevelBuilderWorker.cpp @@ -30,7 +30,7 @@ namespace LevelBuilder { const char s_materialExtension[] = ".mtl"; - const char s_audioControlFilesLevelPath[] = "@devassets@/libs/gameaudio/wwise/levels/%s"; + const char s_audioControlFilesLevelPath[] = "@projectroot@/libs/gameaudio/wwise/levels/%s"; const char s_audioControlFilter[] = "*.xml"; AZ::u64 readXmlDataLength(AZ::IO::GenericStream* stream, int& charSize) diff --git a/Gems/LmbrCentral/Code/Source/Builders/MaterialBuilder/MaterialBuilderComponent.cpp b/Gems/LmbrCentral/Code/Source/Builders/MaterialBuilder/MaterialBuilderComponent.cpp index c06b21337b..48973b2779 100644 --- a/Gems/LmbrCentral/Code/Source/Builders/MaterialBuilder/MaterialBuilderComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Builders/MaterialBuilder/MaterialBuilderComponent.cpp @@ -28,7 +28,7 @@ namespace MaterialBuilder const char g_nodeNameTexture[] = "Texture"; const char g_nodeNameTextures[] = "Textures"; const char g_attributeFileName[] = "File"; - + const int g_numSourceImageFormats = 9; const char* g_sourceImageFormats[g_numSourceImageFormats] = { ".tif", ".tiff", ".bmp", ".gif", ".jpg", ".jpeg", ".tga", ".png", ".dds" }; bool IsSupportedImageExtension(const AZStd::string& extension) @@ -66,7 +66,7 @@ namespace MaterialBuilder return actualFileName; } - // Parses the material XML for all texture paths + // Parses the material XML for all texture paths AZ::Outcome GetTexturePathsFromMaterial(AZ::rapidxml::xml_node* materialNode, AZStd::vector& paths) { AZ::Outcome resultOutcome = AZ::Failure(AZStd::string("")); @@ -94,7 +94,7 @@ namespace MaterialBuilder // do an initial clean-up of the path taken from the file, similar to MaterialHelpers::SetTexturesFromXml AZStd::string texturePath = CleanLegacyPathingFromTexturePath(rawTexturePath); paths.emplace_back(AZStd::move(texturePath)); - } + } textureNode = textureNode->next_sibling(g_nodeNameTexture); } while (textureNode); @@ -112,7 +112,7 @@ namespace MaterialBuilder return AZ::Failure(AZStd::string("SubMaterials node exists but does not have any child Material nodes.")); } - do + do { // grab the texture paths from the submaterial, or error out if necessary AZ::Outcome subMaterialTexturePathsResult = GetTexturePathsFromMaterial(subMaterialNode, paths); @@ -142,7 +142,7 @@ namespace MaterialBuilder } // find a sequence of digits with a string starting from lastDigitIndex, and try to parse that sequence to and int - // and store it in outAnimIndex. + // and store it in outAnimIndex. bool ParseFilePathForCompleteNumber(const AZStd::string& filePath, int& lastDigitIndex, int& outAnimIndex) { int firstAnimIndexDigit = lastDigitIndex; @@ -162,7 +162,7 @@ namespace MaterialBuilder AZ::Outcome GetAllTexturesInTextureSequence(const AZStd::string& path, AZStd::vector& texturesInSequence) { // Taken from CShaderMan::mfReadTexSequence - // All comments next to variable declarations in this function are the original variable names in + // All comments next to variable declarations in this function are the original variable names in // CShaderMan::mfReadTexSequence, to help keep track of how these variables relate to the original function AZStd::string prefix; AZStd::string postfix; @@ -172,7 +172,7 @@ namespace MaterialBuilder AzFramework::StringFunc::Path::GetExtension(filePath.c_str(), extension); AzFramework::StringFunc::Path::StripExtension(filePath); - // unsure if it is actually possible to enter here or the original version with '$' as the indicator + // unsure if it is actually possible to enter here or the original version with '$' as the indicator // for texture sequences, but they check for both just in case, so this will match the behavior. char separator = '#'; // chSep int firstSeparatorIndex = static_cast(filePath.find(separator)); @@ -186,7 +186,7 @@ namespace MaterialBuilder separator = '$'; } - // we don't actually care about getting the speed of the animation, so just remove everything from the + // we don't actually care about getting the speed of the animation, so just remove everything from the // end of the string starting with the last open parenthesis size_t speedStartIndex = filePath.find_last_of('('); if (speedStartIndex != AZStd::string::npos) @@ -195,7 +195,7 @@ namespace MaterialBuilder AzFramework::StringFunc::Append(filePath, '\0'); } - // try to find where the digits start after the separator (there can be any number of separators + // try to find where the digits start after the separator (there can be any number of separators // between the texture name prefix and where the digit range starts) int firstAnimIndexDigit = -1; // m int numSeparators = 0; // j @@ -219,7 +219,7 @@ namespace MaterialBuilder { return AZ::Failure(AZStd::string("Failed to find separator '#' or '$' in texture path.")); } - + // store off everything before the separator prefix = AZStd::move(filePath.substr(0, firstSeparatorIndex)); @@ -242,7 +242,7 @@ namespace MaterialBuilder // reset to the start of the next index ++lastDigitIndex; - + // find the length of the end index, then parse that to an int if (!ParseFilePathForCompleteNumber(filePath, lastDigitIndex, endAnimIndex)) { @@ -262,8 +262,8 @@ namespace MaterialBuilder return AZ::Success(); } - - // Determine which product path to use based on the path stored in the texture, and make it relative to + + // Determine which product path to use based on the path stored in the texture, and make it relative to // the cache. bool ResolveMaterialTexturePath(const AZStd::string& path, AZStd::string& outPath) { @@ -272,7 +272,7 @@ namespace MaterialBuilder //if its a source image format try to load the dds AZStd::string extension; bool hasExtension = AzFramework::StringFunc::Path::GetExtension(path.c_str(), extension); - + // Replace all supported extensions with DDS if it has an extension. If the extension exists but is not supported, fail out. if (hasExtension && IsSupportedImageExtension(extension)) { @@ -286,17 +286,17 @@ namespace MaterialBuilder AZStd::to_lower(aliasedPath.begin(), aliasedPath.end()); AzFramework::StringFunc::Path::Normalize(aliasedPath); - + AZStd::string currentFolderSpecifier = AZStd::string::format(".%c", AZ_CORRECT_FILESYSTEM_SEPARATOR); if (AzFramework::StringFunc::StartsWith(aliasedPath, currentFolderSpecifier)) { AzFramework::StringFunc::Strip(aliasedPath, currentFolderSpecifier.c_str(), false, true); } - + AZStd::string resolvedPath; char fullPathBuffer[AZ_MAX_PATH_LEN] = {}; - // if there is an alias already at the front of the path, resolve it, and try to make it relative to the - // cache (@assets@). If it can't, then error out. + // if there is an alias already at the front of the path, resolve it, and try to make it relative to the + // cache (@products@). If it can't, then error out. // This case handles the possibility of aliases existing in texture paths in materials that is still supported // by the legacy loading code, however it is not currently used, so the else path is always taken. if (aliasedPath[0] == '@') @@ -308,7 +308,7 @@ namespace MaterialBuilder } resolvedPath = fullPathBuffer; AzFramework::StringFunc::Path::Normalize(resolvedPath); - if (!AzFramework::StringFunc::Replace(resolvedPath, AZ::IO::FileIOBase::GetDirectInstance()->GetAlias("@assets@"), "")) + if (!AzFramework::StringFunc::Replace(resolvedPath, AZ::IO::FileIOBase::GetDirectInstance()->GetAlias("@products@"), "")) { AZ_Warning(s_materialBuilder, false, "Failed to resolve aliased texture path %s to be relative to the asset cache. Please make sure this alias resolves to a path within the asset cache.", aliasedPath.c_str()); return false; @@ -318,7 +318,7 @@ namespace MaterialBuilder { resolvedPath = AZStd::move(aliasedPath); } - + // AP deferred path resolution requires UNIX separators and no leading separators, so clean up and convert here if (AzFramework::StringFunc::StartsWith(resolvedPath, AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING)) { @@ -357,7 +357,7 @@ namespace MaterialBuilder // (optimization) this builder does not emit source dependencies: builderDescriptor.m_flags |= AssetBuilderSDK::AssetBuilderDesc::BF_EmitsNoDependencies; - + m_materialBuilder.BusConnect(builderDescriptor.m_busId); EBUS_EVENT(AssetBuilderSDK::AssetBuilderBus, RegisterBuilderInformation, builderDescriptor); @@ -548,10 +548,10 @@ namespace MaterialBuilder } } - // for each texture in the file + // for each texture in the file for (const AZStd::string& texPath : texturePaths) { - // if the texture path starts with a '$' then it is a special runtime defined texture, so it it doesn't have + // if the texture path starts with a '$' then it is a special runtime defined texture, so it it doesn't have // an actual asset on disk to depend on. If the texture path doesn't have an extension, then it is a texture // that is determined at runtime (such as 'nearest_cubemap'), so also ignore those, as other things pull in // those dependencies. @@ -567,7 +567,7 @@ namespace MaterialBuilder AZ_Warning(s_materialBuilder, false, "Failed to resolve texture path %s to a product path when gathering dependencies for %s. Registering dependencies on this texture path will be skipped.", texPath.c_str(), path.c_str()); continue; } - + resolvedPaths.emplace_back(AZStd::move(resolvedPath)); } diff --git a/Gems/LmbrCentral/Code/Source/Bundling/BundlingSystemComponent.cpp b/Gems/LmbrCentral/Code/Source/Bundling/BundlingSystemComponent.cpp index 20386e0628..c9fc656488 100644 --- a/Gems/LmbrCentral/Code/Source/Bundling/BundlingSystemComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Bundling/BundlingSystemComponent.cpp @@ -22,7 +22,7 @@ namespace LmbrCentral { - const char bundleRoot[] = "@assets@"; + const char bundleRoot[] = "@products@"; void BundlingSystemComponent::Activate() { @@ -178,7 +178,7 @@ namespace LmbrCentral // Not already opened, new entry m_openedBundles[bundleName] = AZStd::make_unique(); - AZStd::shared_ptr nextCatalog; // Not all bundles will have catalogs - some are legacy. + AZStd::shared_ptr nextCatalog; // Not all bundles will have catalogs - some are legacy. if (nextBundle == nullptr) { // Added to the end diff --git a/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp b/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp index 31cf68e9a0..a5884ccce9 100644 --- a/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp +++ b/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp @@ -484,7 +484,7 @@ namespace LmbrCentral } // load the catalog from disk (supported over VFS). - EBUS_EVENT(AZ::Data::AssetCatalogRequestBus, LoadCatalog, AZStd::string::format("@assets@/%s", s_assetCatalogFilename).c_str()); + EBUS_EVENT(AZ::Data::AssetCatalogRequestBus, LoadCatalog, AZStd::string::format("@products@/%s", s_assetCatalogFilename).c_str()); } void LmbrCentralSystemComponent::OnCrySystemShutdown([[maybe_unused]] ISystem& system) diff --git a/Gems/LmbrCentral/Code/Tests/Builders/CopyDependencyBuilderTest.cpp b/Gems/LmbrCentral/Code/Tests/Builders/CopyDependencyBuilderTest.cpp index 65847a7fef..8b697f35f2 100644 --- a/Gems/LmbrCentral/Code/Tests/Builders/CopyDependencyBuilderTest.cpp +++ b/Gems/LmbrCentral/Code/Tests/Builders/CopyDependencyBuilderTest.cpp @@ -69,7 +69,7 @@ namespace UnitTest AZ::IO::Path assetRoot(AZ::Utils::GetProjectPath()); assetRoot /= "Cache"; - AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", assetRoot.c_str()); + AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", assetRoot.c_str()); SerializeContext* serializeContext; ComponentApplicationBus::BroadcastResult(serializeContext, &ComponentApplicationRequests::GetSerializeContext); @@ -114,7 +114,7 @@ namespace UnitTest { AssetBuilderSDK::ProductPathDependencySet resolvedPaths; AZStd::vector productDependencies; - + AssetBuilderSDK::ProcessJobRequest request; request.m_fullPath = GetFullPath(fileName); request.m_sourceFile = fileName; @@ -211,8 +211,6 @@ namespace UnitTest ////////////////////////////////////////////////////////////////////////// // AzToolsFramework::AssetSystem::AssetSystemRequestBus::Handler overrides - const char* GetAbsoluteDevGameFolderPath() override { return ""; } - const char* GetAbsoluteDevRootFolderPath() override { return ""; } bool GetRelativeProductPathFromFullSourceOrProductPath([[maybe_unused]] const AZStd::string& fullPath, [[maybe_unused]] AZStd::string& relativeProductPath) override { return true; } bool GenerateRelativeSourcePath( [[maybe_unused]] const AZStd::string& sourcePath, [[maybe_unused]] AZStd::string& relativePath, @@ -428,7 +426,7 @@ namespace UnitTest "Fonts/fontexample-bolditalic.font" }; - AZStd::string fileName = "Fonts/FontFamilyExample.fontfamily"; + AZStd::string fileName = "Fonts/FontFamilyExample.fontfamily"; FontBuilderWorker builderWorker; @@ -445,7 +443,7 @@ namespace UnitTest AZStd::string fileName = "Fonts/FontExample.font"; FontBuilderWorker builderWorker; - + TestSuccessCase(&builderWorker, fileName, "Fonts/FontExample.ttf"); } @@ -667,7 +665,7 @@ namespace UnitTest builderWorker.AddSchemaFileDirectory(GetFullPath("Xmls/Schema/WithoutVersionConstraints/OptionalAttribute")); AZStd::vector expectedProductDependencies; - + TestSuccessCase(&builderWorker, fileName, expectedPaths, expectedProductDependencies); } @@ -896,7 +894,7 @@ namespace UnitTest AssetBuilderSDK::CreateJobsResponse response; request.m_sourceFile = "Tests/Xmls/XmlExampleWithoutVersion.xml"; - request.m_watchFolder = "@root@/../Gems/LmbrCentral/Code/"; + request.m_watchFolder = "@engroot@/Gems/LmbrCentral/Code/"; XmlBuilderWorker builderWorker; builderWorker.AddSchemaFileDirectory(GetFullPath("Xmls/Schema/WithoutVersionConstraints/FullFeatured")); diff --git a/Gems/LmbrCentral/Code/Tests/Builders/LevelBuilderTest.cpp b/Gems/LmbrCentral/Code/Tests/Builders/LevelBuilderTest.cpp index 1fd17e25ce..e50fbbe56c 100644 --- a/Gems/LmbrCentral/Code/Tests/Builders/LevelBuilderTest.cpp +++ b/Gems/LmbrCentral/Code/Tests/Builders/LevelBuilderTest.cpp @@ -104,7 +104,7 @@ namespace UnitTest m_app.Start(m_descriptor); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); AZ::Debug::TraceMessageBus::Handler::BusConnect(); @@ -114,7 +114,7 @@ namespace UnitTest AZ::IO::Path assetRoot(AZ::Utils::GetProjectPath()); assetRoot /= "Cache"; - AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", assetRoot.c_str()); + AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", assetRoot.c_str()); auto* serializeContext = m_app.GetSerializeContext(); @@ -142,7 +142,7 @@ namespace UnitTest AZStd::string GetTestFileAliasedPath(AZStd::string_view fileName) { - constexpr char testFileFolder[] = "@devroot@/Gems/LmbrCentral/Code/Tests/Levels/"; + constexpr char testFileFolder[] = "@engroot@/Gems/LmbrCentral/Code/Tests/Levels/"; return AZStd::string::format("%s%.*s", testFileFolder, aznumeric_cast(fileName.size()), fileName.data()); } diff --git a/Gems/LmbrCentral/Code/Tests/Builders/LuaBuilderTests.cpp b/Gems/LmbrCentral/Code/Tests/Builders/LuaBuilderTests.cpp index 9e077c113c..a9b36d4624 100644 --- a/Gems/LmbrCentral/Code/Tests/Builders/LuaBuilderTests.cpp +++ b/Gems/LmbrCentral/Code/Tests/Builders/LuaBuilderTests.cpp @@ -36,7 +36,7 @@ namespace UnitTest m_app.Start(m_descriptor); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); @@ -45,7 +45,7 @@ namespace UnitTest AZ::IO::Path assetRoot(AZ::Utils::GetProjectPath()); assetRoot /= "Cache"; - AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", assetRoot.c_str()); + AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", assetRoot.c_str()); } void TearDown() override diff --git a/Gems/LmbrCentral/Code/Tests/Builders/MaterialBuilderTests.cpp b/Gems/LmbrCentral/Code/Tests/Builders/MaterialBuilderTests.cpp index 225168ecaa..3786ef7565 100644 --- a/Gems/LmbrCentral/Code/Tests/Builders/MaterialBuilderTests.cpp +++ b/Gems/LmbrCentral/Code/Tests/Builders/MaterialBuilderTests.cpp @@ -35,7 +35,7 @@ namespace UnitTest m_app.reset(aznew AzToolsFramework::ToolsApplication); m_app->Start(AZ::ComponentApplication::Descriptor()); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); AZ::Debug::TraceMessageBus::Handler::BusConnect(); @@ -45,8 +45,7 @@ namespace UnitTest AZ::IO::Path assetRoot(AZ::Utils::GetProjectPath()); assetRoot /= "Cache"; - AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", assetRoot.c_str()); - AZ::IO::FileIOBase::GetInstance()->SetAlias("@assets@", assetRoot.c_str()); + AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", assetRoot.c_str()); } void TearDown() override @@ -128,8 +127,8 @@ namespace UnitTest TEST_F(MaterialBuilderTests, MaterialBuilder_MalformedMaterial_NoChildren_ExpectFailure) { - // Should fail in MaterialBuilderWorker::GetResolvedTexturePathsFromMaterial after calling - // Internal::GetTexturePathsFromMaterial, which should return an AZ::Failure when both a Textures node and a + // Should fail in MaterialBuilderWorker::GetResolvedTexturePathsFromMaterial after calling + // Internal::GetTexturePathsFromMaterial, which should return an AZ::Failure when both a Textures node and a // SubMaterials node are not found. No other AZ_Errors should be generated. TestFailureCase("test_mat2.mtl", 1); } @@ -141,7 +140,7 @@ namespace UnitTest TEST_F(MaterialBuilderTests, MaterialBuilder_MalformedMaterial_EmptySubMaterialNode_ExpectFailure) { - // Should fail in MaterialBuilderWorker::GetResolvedTexturePathsFromMaterial after calling + // Should fail in MaterialBuilderWorker::GetResolvedTexturePathsFromMaterial after calling // Internal::GetTexturePathsFromMaterial, which should return an AZ::Failure when a SubMaterials node is present, // but has no children Material node. No other AZ_Errors should be generated. TestFailureCase("test_mat4.mtl", 1); @@ -154,9 +153,9 @@ namespace UnitTest TEST_F(MaterialBuilderTests, MaterialBuilder_MalformedMaterial_EmptyMaterialInSubMaterial_ExpectFailure) { - // Should fail in MaterialBuilderWorker::GetResolvedTexturePathsFromMaterial after calling + // Should fail in MaterialBuilderWorker::GetResolvedTexturePathsFromMaterial after calling // Internal::GetTexturePathsFromMaterial, which should return an AZ::Failure when a SubMaterials node is present, - // but a child Material node has no child Textures node and no child SubMaterials node. No other AZ_Errors should + // but a child Material node has no child Textures node and no child SubMaterials node. No other AZ_Errors should // be generated. TestFailureCase("test_mat6.mtl", 1); } @@ -235,7 +234,7 @@ namespace UnitTest AZStd::vector expectedPaths = { "engineassets/textures/hex.dds", // resolved from "/engineassets/textures/hex.dds" "engineassets/textures/hex_ddn.dds", // resolved from "./engineassets/textures/hex_ddn.dds" - "engineassets/textures/hex_spec.dds" // resolved from "@assets@/engineassets/textures/hex_spec.dds" + "engineassets/textures/hex_spec.dds" // resolved from "@products@/engineassets/textures/hex_spec.dds" }; TestSuccessCase("test_mat17.mtl", expectedPaths); } diff --git a/Gems/LmbrCentral/Code/Tests/Builders/SeedBuilderTests.cpp b/Gems/LmbrCentral/Code/Tests/Builders/SeedBuilderTests.cpp index 0d70e34701..f679a3502d 100644 --- a/Gems/LmbrCentral/Code/Tests/Builders/SeedBuilderTests.cpp +++ b/Gems/LmbrCentral/Code/Tests/Builders/SeedBuilderTests.cpp @@ -24,16 +24,16 @@ class SeedBuilderTests AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/project_path"; registry->Set(projectPathKey, "AutomatedTesting"); AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*registry); - + m_app.Start(AZ::ComponentApplication::Descriptor()); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); const char* dir = m_app.GetExecutableFolder(); - AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", dir); + AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", dir); AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); } @@ -49,7 +49,7 @@ TEST_F(SeedBuilderTests, SeedBuilder_SourceDependency_Valid) { DependencyBuilder::SeedBuilderWorker seedBuilderWorker; AssetBuilderSDK::CreateJobsRequest request; - constexpr char testSeedFolder[] = "@root@/../Gems/LmbrCentral/Code/Tests/Seed"; + constexpr char testSeedFolder[] = "@engroot@/Gems/LmbrCentral/Code/Tests/Seed"; char resolvedPath[AZ_MAX_PATH_LEN]; AZ::IO::FileIOBase::GetInstance()->ResolvePath(testSeedFolder, resolvedPath, AZ_MAX_PATH_LEN); request.m_watchFolder = resolvedPath; @@ -78,7 +78,7 @@ TEST_F(SeedBuilderTests, SeedBuilder_EmptySourceDependency_Valid) { DependencyBuilder::SeedBuilderWorker seedBuilderWorker; AssetBuilderSDK::CreateJobsRequest request; - constexpr char testSeedFolder[] = "@root@/../Gems/LmbrCentral/Code/Tests/Seed"; + constexpr char testSeedFolder[] = "@engroot@/Gems/LmbrCentral/Code/Tests/Seed"; char resolvedPath[AZ_MAX_PATH_LEN]; AZ::IO::FileIOBase::GetInstance()->ResolvePath(testSeedFolder, resolvedPath, AZ_MAX_PATH_LEN); request.m_watchFolder = resolvedPath; diff --git a/Gems/LmbrCentral/Code/Tests/BundlingSystemComponentTests.cpp b/Gems/LmbrCentral/Code/Tests/BundlingSystemComponentTests.cpp index 08251eb716..7275909908 100644 --- a/Gems/LmbrCentral/Code/Tests/BundlingSystemComponentTests.cpp +++ b/Gems/LmbrCentral/Code/Tests/BundlingSystemComponentTests.cpp @@ -52,7 +52,7 @@ namespace UnitTest { return false; } - + AZ::Data::AssetInfo assetInfo; AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetInfo, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetInfoById, testAssetId); return assetInfo.m_relativePath == assetPath; @@ -61,7 +61,7 @@ namespace UnitTest TEST_F(Integ_BundlingSystemComponentFixture, HasBundle_LoadBundles_Success) { - // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our + // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our // cache as test/bundle/staticdata.pak and should be loaded below const char testAssetPath[] = "staticdata/csv/bundlingsystemtestgameproperties.csv"; @@ -74,7 +74,7 @@ namespace UnitTest TEST_F(Integ_BundlingSystemComponentFixture, HasBundle_LoadBundlesCatalogChecks_Success) { - // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our + // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our // cache as test/bundle/staticdata.pak and should be loaded below // The Pak has a catalog describing the contents which should automatically update our central asset catalog const char testAssetPath[] = "staticdata/csv/bundlingsystemtestgameproperties.csv"; @@ -94,34 +94,34 @@ namespace UnitTest TEST_F(Integ_BundlingSystemComponentFixture, BundleSystemComponent_SingleUnloadCheckCatalog_Success) { - // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our + // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our // cache as test/bundle/staticdata.pak and should be loaded below // The Pak has a catalog describing the contents which should automatically update our central asset catalog const char testCSVAsset[] = "staticdata/csv/bundlingsystemtestgameproperties.csv"; const char testCSVAssetPak[] = "test/bundle/staticdata.pak"; - // This asset lives only within LmbrCentral/Assets/Test/Bundle/ping.pak + // This asset lives only within LmbrCentral/Assets/Test/Bundle/ping.pak const char testDDSAsset[] = "textures/test/ping.dds"; const char testDDSAssetPak[] = "test/bundle/ping.pak"; EXPECT_FALSE(TestAssetId(testCSVAsset)); EXPECT_FALSE(TestAssetId(testDDSAsset)); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testDDSAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testDDSAssetPak)); EXPECT_FALSE(TestAssetId(testCSVAsset)); EXPECT_TRUE(TestAssetId(testDDSAsset)); EXPECT_TRUE(gEnv->pCryPak->ClosePack(testDDSAssetPak)); EXPECT_FALSE(TestAssetId(testCSVAsset)); EXPECT_FALSE(TestAssetId(testDDSAsset)); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testCSVAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testCSVAssetPak)); EXPECT_TRUE(TestAssetId(testCSVAsset)); EXPECT_FALSE(TestAssetId(testDDSAsset)); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testDDSAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testDDSAssetPak)); EXPECT_TRUE(TestAssetId(testCSVAsset)); EXPECT_TRUE(TestAssetId(testDDSAsset)); EXPECT_TRUE(gEnv->pCryPak->ClosePack(testDDSAssetPak)); EXPECT_TRUE(TestAssetId(testCSVAsset)); EXPECT_FALSE(TestAssetId(testDDSAsset)); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testDDSAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testDDSAssetPak)); EXPECT_TRUE(TestAssetId(testCSVAsset)); EXPECT_TRUE(TestAssetId(testDDSAsset)); EXPECT_TRUE(gEnv->pCryPak->ClosePack(testCSVAssetPak)); @@ -134,7 +134,7 @@ namespace UnitTest TEST_F(Integ_BundlingSystemComponentFixture, BundleSystemComponent_SingleLoadAndBundleMode_Success) { - // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our + // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our // cache as test/bundle/staticdata.pak and should be loaded below // The Pak has a catalog describing the contents which should automatically update our central asset catalog const char testCSVAsset[] = "staticdata/csv/bundlingsystemtestgameproperties.csv"; @@ -143,7 +143,7 @@ namespace UnitTest const char testMTLAssetPak[] = "test/TestMaterials.pak"; EXPECT_FALSE(TestAssetId(testCSVAsset)); EXPECT_FALSE(TestAssetId(testMTLAsset)); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testMTLAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testMTLAssetPak)); EXPECT_FALSE(TestAssetId(testCSVAsset)); EXPECT_TRUE(TestAssetId(testMTLAsset)); LmbrCentral::BundlingSystemRequestBus::Broadcast(&LmbrCentral::BundlingSystemRequestBus::Events::LoadBundles, "test/bundle", ".pak"); @@ -159,35 +159,35 @@ namespace UnitTest TEST_F(Integ_BundlingSystemComponentFixture, BundleSystemComponent_OpenClosePackCount_Match) { - // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our + // This asset lives only within LmbrCentral/Assets/Test/Bundle/staticdata.pak which is copied to our // cache as test/bundle/staticdata.pak and should be loaded below // The Pak has a catalog describing the contents which should automatically update our central asset catalog const char testCSVAsset[] = "staticdata/csv/bundlingsystemtestgameproperties.csv"; const char testCSVAssetPak[] = "test/bundle/staticdata.pak"; - // This asset lives only within LmbrCentral/Assets/Test/Bundle/ping.pak + // This asset lives only within LmbrCentral/Assets/Test/Bundle/ping.pak const char testDDSAssetPak[] = "test/bundle/ping.pak"; size_t bundleCount{ 0 }; LmbrCentral::BundlingSystemRequestBus::BroadcastResult(bundleCount,&LmbrCentral::BundlingSystemRequestBus::Events::GetOpenedBundleCount); EXPECT_EQ(bundleCount, 0); EXPECT_FALSE(TestAssetId(testCSVAsset)); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testDDSAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testDDSAssetPak)); LmbrCentral::BundlingSystemRequestBus::BroadcastResult(bundleCount, &LmbrCentral::BundlingSystemRequestBus::Events::GetOpenedBundleCount); EXPECT_EQ(bundleCount, 1); EXPECT_TRUE(gEnv->pCryPak->ClosePack(testDDSAssetPak)); LmbrCentral::BundlingSystemRequestBus::BroadcastResult(bundleCount, &LmbrCentral::BundlingSystemRequestBus::Events::GetOpenedBundleCount); EXPECT_EQ(bundleCount, 0); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testCSVAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testCSVAssetPak)); LmbrCentral::BundlingSystemRequestBus::BroadcastResult(bundleCount, &LmbrCentral::BundlingSystemRequestBus::Events::GetOpenedBundleCount); EXPECT_EQ(bundleCount, 1); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testDDSAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testDDSAssetPak)); LmbrCentral::BundlingSystemRequestBus::BroadcastResult(bundleCount, &LmbrCentral::BundlingSystemRequestBus::Events::GetOpenedBundleCount); EXPECT_EQ(bundleCount, 2); EXPECT_TRUE(gEnv->pCryPak->ClosePack(testDDSAssetPak)); LmbrCentral::BundlingSystemRequestBus::BroadcastResult(bundleCount, &LmbrCentral::BundlingSystemRequestBus::Events::GetOpenedBundleCount); EXPECT_EQ(bundleCount, 1); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testDDSAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testDDSAssetPak)); LmbrCentral::BundlingSystemRequestBus::BroadcastResult(bundleCount, &LmbrCentral::BundlingSystemRequestBus::Events::GetOpenedBundleCount); EXPECT_EQ(bundleCount, 2); EXPECT_TRUE(gEnv->pCryPak->ClosePack(testCSVAssetPak)); @@ -208,7 +208,7 @@ namespace UnitTest LmbrCentral::BundlingSystemRequestBus::BroadcastResult(bundleCount, &LmbrCentral::BundlingSystemRequestBus::Events::GetOpenedBundleCount); EXPECT_EQ(bundleCount, 0); EXPECT_FALSE(TestAssetId(testDDSAsset_split)); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testDDSAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testDDSAssetPak)); LmbrCentral::BundlingSystemRequestBus::BroadcastResult(bundleCount, &LmbrCentral::BundlingSystemRequestBus::Events::GetOpenedBundleCount); EXPECT_EQ(bundleCount, 2); EXPECT_TRUE(TestAssetId(testDDSAsset_split)); @@ -217,7 +217,7 @@ namespace UnitTest EXPECT_EQ(bundleCount, 0); EXPECT_FALSE(TestAssetId(testDDSAsset_split)); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testDDSAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testDDSAssetPak)); LmbrCentral::BundlingSystemRequestBus::BroadcastResult(bundleCount, &LmbrCentral::BundlingSystemRequestBus::Events::GetOpenedBundleCount); EXPECT_EQ(bundleCount, 2); EXPECT_TRUE(TestAssetId(testDDSAsset_split)); @@ -240,7 +240,7 @@ namespace UnitTest EXPECT_FALSE(TestAssetId(testGamePropertiesAsset)); EXPECT_FALSE(TestAssetId(testUserRequestAsset)); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testGamePropertiesAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testGamePropertiesAssetPak)); EXPECT_TRUE(TestAssetId(testGamePropertiesAsset)); EXPECT_FALSE(TestAssetId(testUserRequestAsset)); AZ::Data::AssetId testAssetId; @@ -253,7 +253,7 @@ namespace UnitTest EXPECT_NE(assetInfo.m_sizeBytes, 0); AZ::u64 assetSize1 = assetInfo.m_sizeBytes; - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testUserRequestAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testUserRequestAssetPak)); EXPECT_TRUE(TestAssetId(testGamePropertiesAsset)); EXPECT_TRUE(TestAssetId(testUserRequestAsset)); @@ -271,13 +271,13 @@ namespace UnitTest EXPECT_FALSE(TestAssetId(testGamePropertiesAsset)); EXPECT_FALSE(TestAssetId(testUserRequestAsset)); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testUserRequestAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testUserRequestAssetPak)); AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetInfo, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetInfoById, testAssetId); AZ::u64 assetSize3 = assetInfo.m_sizeBytes; EXPECT_EQ(assetSize3, assetSize2); - EXPECT_TRUE(gEnv->pCryPak->OpenPack("@assets@", testGamePropertiesAssetPak)); + EXPECT_TRUE(gEnv->pCryPak->OpenPack("@products@", testGamePropertiesAssetPak)); AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetInfo, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetInfoById, testAssetId); AZ::u64 assetSize4 = assetInfo.m_sizeBytes; EXPECT_EQ(assetSize4, assetSize1); diff --git a/Gems/LmbrCentral/Code/Tests/EmfxWorkSpace/productdependencies.emfxworkspace b/Gems/LmbrCentral/Code/Tests/EmfxWorkSpace/productdependencies.emfxworkspace index 6c7f7d3d87..0e92f9e83c 100644 --- a/Gems/LmbrCentral/Code/Tests/EmfxWorkSpace/productdependencies.emfxworkspace +++ b/Gems/LmbrCentral/Code/Tests/EmfxWorkSpace/productdependencies.emfxworkspace @@ -1,3 +1,3 @@ [General] version=1 -startScript="ImportActor -filename \"@assets@/foo.actor\"\nCreateActorInstance -actorID %LASTRESULT% -xPos 0.000000 -yPos 0.000000 -zPos 0.000000 -xScale 1.000000 -yScale 1.000000 -zScale 1.000000 -rot 0.00000000,0.00000000,0.00000000,1.00015891\nLoadMotionSet -filename \"@assets@/foo.motionset\"\nLoadAnimGraph -filename \"@assets@/foo.animgraph\"\nActivateAnimGraph -actorInstanceID %LASTRESULT3% -animGraphID %LASTRESULT1% -motionSetID %LASTRESULT2% -visualizeScale 1.000000\n" +startScript="ImportActor -filename \"@products@/foo.actor\"\nCreateActorInstance -actorID %LASTRESULT% -xPos 0.000000 -yPos 0.000000 -zPos 0.000000 -xScale 1.000000 -yScale 1.000000 -zScale 1.000000 -rot 0.00000000,0.00000000,0.00000000,1.00015891\nLoadMotionSet -filename \"@products@/foo.motionset\"\nLoadAnimGraph -filename \"@products@/foo.animgraph\"\nActivateAnimGraph -actorInstanceID %LASTRESULT3% -animGraphID %LASTRESULT1% -motionSetID %LASTRESULT2% -visualizeScale 1.000000\n" diff --git a/Gems/LmbrCentral/Code/Tests/Materials/test_mat17.mtl b/Gems/LmbrCentral/Code/Tests/Materials/test_mat17.mtl index 099e006f4c..c3d0ddcf61 100644 --- a/Gems/LmbrCentral/Code/Tests/Materials/test_mat17.mtl +++ b/Gems/LmbrCentral/Code/Tests/Materials/test_mat17.mtl @@ -2,7 +2,7 @@ - + diff --git a/Gems/LyShine/Code/Editor/EditorMenu.cpp b/Gems/LyShine/Code/Editor/EditorMenu.cpp index 8a6c93de6b..0eeec9a06e 100644 --- a/Gems/LyShine/Code/Editor/EditorMenu.cpp +++ b/Gems/LyShine/Code/Editor/EditorMenu.cpp @@ -606,7 +606,7 @@ void EditorWindow::AddMenu_View() [this]([[maybe_unused]] bool checked) { // Clear guides - AZStd::string canvasUndoXml = CanvasHelpers::BeginUndoableCanvasChange(GetCanvas()); + AZStd::string canvasUndoXml = CanvasHelpers::BeginUndoableCanvasChange(GetCanvas()); EBUS_EVENT_ID(GetCanvas(), UiEditorCanvasBus, RemoveAllGuides); CanvasHelpers::EndUndoableCanvasChange(this, "clear guides", canvasUndoXml); }); @@ -724,7 +724,7 @@ void EditorWindow::AddMenu_View_LanguageSetting(QMenu* viewMenu) // Iterate through the subdirectories of the localization folder. Each // directory corresponds to a different language containing localization // translations for that language. - AZStd::string fullLocPath(AZStd::string(gEnv->pFileIO->GetAlias("@assets@")) + "/" + AZStd::string(m_startupLocFolderName.toUtf8().constData())); + AZStd::string fullLocPath(AZStd::string(gEnv->pFileIO->GetAlias("@products@")) + "/" + AZStd::string(m_startupLocFolderName.toUtf8().constData())); QDir locDir(fullLocPath.c_str()); locDir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot); locDir.setSorting(QDir::Name); @@ -733,7 +733,7 @@ void EditorWindow::AddMenu_View_LanguageSetting(QMenu* viewMenu) { QString directoryName(subDirectory.fileName().toLower()); - // The loc system expects XML assets stored in a language-specific + // The loc system expects XML assets stored in a language-specific // folder with an "_xml" suffix in the name. Truncate the displayed // name so the user just sees the language name (this isn't required // though). @@ -754,7 +754,7 @@ void EditorWindow::AddMenu_View_LanguageSetting(QMenu* viewMenu) { // First try to locate the directory by name, without the "_xml" // suffix (in case it actually exists by this name). - QString fullLocPath(QString(gEnv->pFileIO->GetAlias("@assets@")) + "/" + m_startupLocFolderName + "/" + directoryName); + QString fullLocPath(QString(gEnv->pFileIO->GetAlias("@products@")) + "/" + m_startupLocFolderName + "/" + directoryName); QDir locDir(fullLocPath); // Try the directory with the expected suffix @@ -780,7 +780,7 @@ void EditorWindow::AddMenu_View_LanguageSetting(QMenu* viewMenu) "This used to be set to CSystem::OnLocalizationFolderCVarChanged but is now missing. " "UI Editor language-switching features are no longer working."); } - + // Update the language setting; this will allow font families to // load language-specific font assets ICVar* languageCvar = gEnv->pConsole->GetCVar("g_language"); diff --git a/Gems/LyShine/Code/Editor/UiSliceManager.cpp b/Gems/LyShine/Code/Editor/UiSliceManager.cpp index 97e9a51e11..a8fdad5343 100644 --- a/Gems/LyShine/Code/Editor/UiSliceManager.cpp +++ b/Gems/LyShine/Code/Editor/UiSliceManager.cpp @@ -138,7 +138,7 @@ void UiSliceManager::MakeSliceFromEntities(AzToolsFramework::EntityIdList& entit // expand the list of entities to include all child entities AzToolsFramework::EntityIdSet entitiesAndDescendants = GatherEntitiesAndAllDescendents(entities); - const AZStd::string slicesAssetsPath = "@devassets@/UI/Slices"; + const AZStd::string slicesAssetsPath = "@projectroot@/UI/Slices"; if (!gEnv->pFileIO->Exists(slicesAssetsPath.c_str())) { @@ -991,13 +991,13 @@ AZStd::string UiSliceManager::MakeTemporaryFilePathForSave(const char* targetFil AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); AZ_Assert(fileIO, "File IO is not initialized."); - AZStd::string devAssetPath = fileIO->GetAlias("@devassets@"); + AZStd::string devAssetPath = fileIO->GetAlias("@projectroot@"); AZStd::string userPath = fileIO->GetAlias("@user@"); AZStd::string tempPath = targetFilename; EBUS_EVENT(AzFramework::ApplicationRequests::Bus, NormalizePath, devAssetPath); EBUS_EVENT(AzFramework::ApplicationRequests::Bus, NormalizePath, userPath); EBUS_EVENT(AzFramework::ApplicationRequests::Bus, NormalizePath, tempPath); - AzFramework::StringFunc::Replace(tempPath, "@devassets@", devAssetPath.c_str()); + AzFramework::StringFunc::Replace(tempPath, "@projectroot@", devAssetPath.c_str()); AzFramework::StringFunc::Replace(tempPath, devAssetPath.c_str(), userPath.c_str()); tempPath.append(".slicetemp"); diff --git a/Gems/LyShine/Code/Source/UiCanvasManager.cpp b/Gems/LyShine/Code/Source/UiCanvasManager.cpp index a71c46d45e..f2397248b6 100644 --- a/Gems/LyShine/Code/Source/UiCanvasManager.cpp +++ b/Gems/LyShine/Code/Source/UiCanvasManager.cpp @@ -67,7 +67,7 @@ namespace // Check if extension needs to be fixed up const AZStd::string canvasExtension("uicanvas"); - bool validExtension = AzFramework::StringFunc::Path::IsExtension(assetPath.c_str(), canvasExtension.c_str(), true); + bool validExtension = AzFramework::StringFunc::Path::IsExtension(assetPath.c_str(), canvasExtension.c_str(), true); if (!validExtension) { // Fix extension @@ -79,7 +79,7 @@ namespace // Normalize path EBUS_EVENT(AzFramework::ApplicationRequests::Bus, NormalizePathKeepCase, assetPath); - // Check for any leading slashes as the specified path should be a relative path to the @assets@ alias. + // Check for any leading slashes as the specified path should be a relative path to the @products@ alias. // This eliminates inconsistencies between lower level file opens on different platforms int numCharsToErase = 0; for (; numCharsToErase < assetPath.length(); ++numCharsToErase) @@ -581,7 +581,7 @@ void UiCanvasManager::UpdateLoadedCanvases(float deltaTime) // Update all the canvases loaded in game. // It is unlikely this will call out to client code that could remove a canvas but we have no - // control over what custom components do so we increment the count that will defer all canvas deletion + // control over what custom components do so we increment the count that will defer all canvas deletion m_recursionGuardCount++; if (m_generateMousePositionInputEvent) { @@ -1087,7 +1087,7 @@ void UiCanvasManager::DebugDisplayCanvasData(int setting) const } const char* enabledString = isCanvasEnabled ? "Y" : "N"; totalEnabled += isCanvasEnabled ? 1 : 0; - + bool posEnabled = canvas->GetIsPositionalInputSupported(); const char* posEnabledString = posEnabled ? "Y" : "N"; totalPositionalInputs += posEnabled ? 1 : 0; @@ -1178,7 +1178,7 @@ void UiCanvasManager::DebugDisplayDrawCallData() const const AZ::Vector3 blue(0.3f,0.3f,1); const AZ::Vector3 green(0.3f,1,0.3f); const AZ::Vector3 yellow(0.7f,0.7f,0.2f); - + // local function to write a line of text (with a background rect) and increment Y offset AZStd::function WriteLine = [&](const char* buffer, const AZ::Vector3& color) { @@ -1191,7 +1191,7 @@ void UiCanvasManager::DebugDisplayDrawCallData() const draw2d->DrawText(buffer, AZ::Vector2(xOffset, yOffset), 16, textOpacity, &textOptions); yOffset += lineSpacing; }; - + char buffer[200]; sprintf_s(buffer, "NN: %20s %5s %5s %5s %5s %5s %5s %5s %5s %5s %5s %5s %5s", diff --git a/Gems/LyShine/Code/Tests/LyShineEditorTest.cpp b/Gems/LyShine/Code/Tests/LyShineEditorTest.cpp index ff4e054ac7..60074ac0a0 100644 --- a/Gems/LyShine/Code/Tests/LyShineEditorTest.cpp +++ b/Gems/LyShine/Code/Tests/LyShineEditorTest.cpp @@ -60,7 +60,7 @@ AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV); using namespace AZ; using ::testing::NiceMock; -class LyShineSystemTestComponent +class LyShineSystemTestComponent : public LyShine::LyShineSystemComponent { friend class LyShineEditorTest; @@ -90,18 +90,18 @@ protected: m_app.Start(m_descriptor); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); const AZStd::string engineRoot = AZ::Test::GetEngineRootPath(); - AZ::IO::FileIOBase::GetInstance()->SetAlias("@engroot@", engineRoot.c_str()); + AZ::IO::FileIOBase::GetInstance()->SetAlias("@engroot@", engineRoot.c_str()); AZ::IO::Path assetRoot(AZ::Utils::GetProjectPath()); assetRoot /= "Cache"; - AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", assetRoot.c_str()); + AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", assetRoot.c_str()); AZ::SerializeContext* context = nullptr; ComponentApplicationBus::BroadcastResult(context, &ComponentApplicationBus::Events::GetSerializeContext); diff --git a/Gems/MessagePopup/Code/Source/LyShineMessagePopup.cpp b/Gems/MessagePopup/Code/Source/LyShineMessagePopup.cpp index 104118e4bf..40fed3448b 100644 --- a/Gems/MessagePopup/Code/Source/LyShineMessagePopup.cpp +++ b/Gems/MessagePopup/Code/Source/LyShineMessagePopup.cpp @@ -127,21 +127,21 @@ namespace MessagePopup switch (_buttons) { case EPopupButtons::EPopupButtons_NoButtons: - canvasEntityId = gEnv->pLyShine->LoadCanvas("@assets@/ui/canvases/defaultmessagepopup.uicanvas"); + canvasEntityId = gEnv->pLyShine->LoadCanvas("@products@/ui/canvases/defaultmessagepopup.uicanvas"); break; case EPopupButtons::EPopupButtons_Confirm: - canvasEntityId = gEnv->pLyShine->LoadCanvas("@assets@/ui/canvases/defaultmessagepopup_confirm.uicanvas"); + canvasEntityId = gEnv->pLyShine->LoadCanvas("@products@/ui/canvases/defaultmessagepopup_confirm.uicanvas"); isNavigationSupported = true; break; case EPopupButtons::EPopupButtons_YesNo: - canvasEntityId = gEnv->pLyShine->LoadCanvas("@assets@/ui/canvases/defaultmessagepopup_yesno.uicanvas"); + canvasEntityId = gEnv->pLyShine->LoadCanvas("@products@/ui/canvases/defaultmessagepopup_yesno.uicanvas"); isNavigationSupported = true; break; } } else if (_kind == EPopupKind_Toaster) { - canvasEntityId = gEnv->pLyShine->LoadCanvas("@assets@/ui/canvases/toaster.uicanvas"); + canvasEntityId = gEnv->pLyShine->LoadCanvas("@products@/ui/canvases/toaster.uicanvas"); } if (canvasEntityId.IsValid()) diff --git a/Gems/PhysXSamples/Assets/Characters/Cowboy/AnimationEditorFiles/Cowboy.emfxworkspace b/Gems/PhysXSamples/Assets/Characters/Cowboy/AnimationEditorFiles/Cowboy.emfxworkspace index 1727656092..8bc507082c 100644 --- a/Gems/PhysXSamples/Assets/Characters/Cowboy/AnimationEditorFiles/Cowboy.emfxworkspace +++ b/Gems/PhysXSamples/Assets/Characters/Cowboy/AnimationEditorFiles/Cowboy.emfxworkspace @@ -1,3 +1,3 @@ [General] version=1 -startScript="ImportActor -filename \"@assets@/characters/cowboy/actor/cowboy_01.actor\"\nCreateActorInstance -actorID %LASTRESULT% -xPos 0.000000 -yPos 0.000000 -zPos 0.000000 -xScale 1.000000 -yScale 1.000000 -zScale 1.000000 -rot 0.00000000,0.00000000,0.00000000,1.00000000\nLoadMotionSet -filename \"@assets@/Characters/Cowboy/AnimationEditorFiles/Cowboy.motionset\"\nLoadAnimGraph -filename \"@assets@/Characters/Cowboy/AnimationEditorFiles/Cowboy.animgraph\"\nActivateAnimGraph -actorInstanceID %LASTRESULT3% -animGraphID %LASTRESULT1% -motionSetID %LASTRESULT2% -visualizeScale 1.000000\n" +startScript="ImportActor -filename \"@products@/characters/cowboy/actor/cowboy_01.actor\"\nCreateActorInstance -actorID %LASTRESULT% -xPos 0.000000 -yPos 0.000000 -zPos 0.000000 -xScale 1.000000 -yScale 1.000000 -zScale 1.000000 -rot 0.00000000,0.00000000,0.00000000,1.00000000\nLoadMotionSet -filename \"@products@/Characters/Cowboy/AnimationEditorFiles/Cowboy.motionset\"\nLoadAnimGraph -filename \"@products@/Characters/Cowboy/AnimationEditorFiles/Cowboy.animgraph\"\nActivateAnimGraph -actorInstanceID %LASTRESULT3% -animGraphID %LASTRESULT1% -motionSetID %LASTRESULT2% -visualizeScale 1.000000\n" diff --git a/Gems/QtForPython/Code/Source/QtForPythonSystemComponent.cpp b/Gems/QtForPython/Code/Source/QtForPythonSystemComponent.cpp index a7bd193fd7..83a158dd18 100644 --- a/Gems/QtForPython/Code/Source/QtForPythonSystemComponent.cpp +++ b/Gems/QtForPython/Code/Source/QtForPythonSystemComponent.cpp @@ -202,9 +202,6 @@ namespace QtForPython QtBootstrapParameters QtForPythonSystemComponent::GetQtBootstrapParameters() const { QtBootstrapParameters params; - - char devroot[AZ_MAX_PATH_LEN]; - AZ::IO::FileIOBase::GetInstance()->ResolvePath("@devroot@", devroot, AZ_MAX_PATH_LEN); #if !defined(Q_OS_WIN) #error Unsupported OS platform for this QtForPython gem diff --git a/Gems/SceneProcessing/Code/Tests/SceneBuilder/SceneBuilderTests.cpp b/Gems/SceneProcessing/Code/Tests/SceneBuilder/SceneBuilderTests.cpp index a4da836aeb..5d0105f080 100644 --- a/Gems/SceneProcessing/Code/Tests/SceneBuilder/SceneBuilderTests.cpp +++ b/Gems/SceneProcessing/Code/Tests/SceneBuilder/SceneBuilderTests.cpp @@ -36,13 +36,12 @@ protected: m_app.Start(AZ::ComponentApplication::Descriptor()); AZ::Debug::TraceMessageBus::Handler::BusConnect(); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash + // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // in the unit tests. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); m_workingDirectory = m_app.GetExecutableFolder(); - AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", m_workingDirectory); - AZ::IO::FileIOBase::GetInstance()->SetAlias("@assets@", m_workingDirectory); + AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", m_workingDirectory); } void TearDown() override @@ -78,7 +77,7 @@ protected: } void TestSuccessCase(const SceneAPI::Events::ExportProduct& exportProduct, - const AssetBuilderSDK::ProductPathDependency* expectedPathDependency = nullptr, + const AssetBuilderSDK::ProductPathDependency* expectedPathDependency = nullptr, const AZ::Uuid* expectedProductDependency = nullptr) { AssetBuilderSDK::ProductPathDependencySet expectedPathDependencies; @@ -86,13 +85,13 @@ protected: { expectedPathDependencies.emplace(*expectedPathDependency); } - + AZStd::vector expectedProductDependencies; if (expectedProductDependency) { expectedProductDependencies.push_back(*expectedProductDependency); } - + TestSuccessCase(exportProduct, expectedPathDependencies, expectedProductDependencies); } @@ -121,7 +120,7 @@ TEST_F(SceneBuilderTests, SceneBuilderWorker_ExportProductDependencies_PathDepen const char* absolutePathToFile = "/some/test/file.mtl"; #endif // AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS AssetBuilderSDK::ProductPathDependency expectedPathDependency(absolutePathToFile, AssetBuilderSDK::ProductPathDependencyType::SourceFile); - + SceneAPI::Events::ExportProduct product("testExportFile", AZ::Uuid::CreateRandom(), AZ::Data::AssetType::CreateNull(), u8(0), AZStd::nullopt); product.m_legacyPathDependencies.push_back(absolutePathToFile); TestSuccessCase(product, &expectedPathDependency); @@ -133,7 +132,7 @@ TEST_F(SceneBuilderTests, SceneBuilderWorker_ExportProductDependencies_PathDepen const char* relativeDependencyPathToFile = "some/test/file.mtl"; AssetBuilderSDK::ProductPathDependency expectedPathDependency(relativeDependencyPathToFile, AssetBuilderSDK::ProductPathDependencyType::ProductFile); - + SceneAPI::Events::ExportProduct product("testExportFile", AZ::Uuid::CreateRandom(), AZ::Data::AssetType::CreateNull(), u8(0), AZStd::nullopt); product.m_legacyPathDependencies.push_back(relativeDependencyPathToFile); diff --git a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasAsset.h b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasAsset.h index fdc8cbc1d8..0fb0f567e8 100644 --- a/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasAsset.h +++ b/Gems/ScriptCanvas/Code/Editor/Include/ScriptCanvas/Assets/ScriptCanvasAsset.h @@ -41,7 +41,7 @@ namespace ScriptCanvasEditor azrtti_typeid(), "Script Canvas", "Script Canvas Graph Asset", - "@devassets@/scriptcanvas", + "@projectroot@/scriptcanvas", ".scriptcanvas", "Script Canvas", "Untitled-%i", diff --git a/Gems/ScriptCanvas/Code/Editor/Utilities/CommonSettingsConfigurations.cpp b/Gems/ScriptCanvas/Code/Editor/Utilities/CommonSettingsConfigurations.cpp index 15cbd12d7e..a7c39fbf0f 100644 --- a/Gems/ScriptCanvas/Code/Editor/Utilities/CommonSettingsConfigurations.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Utilities/CommonSettingsConfigurations.cpp @@ -9,27 +9,20 @@ #include "CommonSettingsConfigurations.h" #include +#include +#include #include namespace ScriptCanvasEditor { AZStd::string GetEditingGameDataFolder() { - const char* resultValue = nullptr; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(resultValue, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetAbsoluteDevGameFolderPath); - if (!resultValue) + AZ::IO::Path projectPath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) { - if (AZ::IO::FileIOBase::GetInstance()) - { - resultValue = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@"); - } + settingsRegistry->Get(projectPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath); } - if (!resultValue) - { - resultValue = "."; - } - - return resultValue; + return projectPath.Native(); } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp index fbe03ffc0a..289643d59c 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.cpp @@ -72,6 +72,7 @@ #include #include #include +#include #include #include #include @@ -224,7 +225,7 @@ namespace ScriptCanvasEditor } } } // anonymous namespace. - + void Workspace::Save() { auto workspace = AZ::UserSettings::CreateFind(AZ_CRC("ScriptCanvasEditorWindowState", 0x10c47d36), AZ::UserSettings::CT_LOCAL); @@ -423,7 +424,7 @@ namespace ScriptCanvasEditor , m_queueCloseRequest(false) , m_hasQueuedClose(false) , m_isInAutomation(false) - , m_allowAutoSave(true) + , m_allowAutoSave(true) , m_systemTickActions(0) , m_closeCurrentGraphAfterSave(false) , m_styleManager(ScriptCanvasEditor::AssetEditorId, "ScriptCanvas/StyleSheet/graphcanvas_style.json") @@ -432,7 +433,7 @@ namespace ScriptCanvasEditor GraphCanvas::AssetEditorAutomationRequestBus::Handler::BusConnect(ScriptCanvasEditor::AssetEditorId); AZStd::array unresolvedPath; - AZ::IO::FileIOBase::GetInstance()->ResolvePath("@assets@/translation/scriptcanvas_en_us.qm", unresolvedPath.data(), unresolvedPath.size()); + AZ::IO::FileIOBase::GetInstance()->ResolvePath("@products@/translation/scriptcanvas_en_us.qm", unresolvedPath.data(), unresolvedPath.size()); QString translationFilePath(unresolvedPath.data()); if ( m_translator.load(QLocale::Language::English, translationFilePath) ) @@ -541,7 +542,7 @@ namespace ScriptCanvasEditor m_editorToolbar->AddCustomAction(m_createFunctionOutput); connect(m_createFunctionOutput, &QToolButton::clicked, this, &MainWindow::CreateFunctionOutput); - + { m_validateGraphToolButton = new QToolButton(); @@ -553,7 +554,7 @@ namespace ScriptCanvasEditor m_editorToolbar->AddCustomAction(m_validateGraphToolButton); connect(m_validateGraphToolButton, &QToolButton::clicked, this, &MainWindow::OnValidateCurrentGraph); - + m_layout->addWidget(m_editorToolbar); // Tab bar @@ -578,7 +579,7 @@ namespace ScriptCanvasEditor m_commandLine = new Widget::CommandLine(this); m_commandLine->setBaseSize(QSize(size().width(), m_commandLine->size().height())); - m_commandLine->setObjectName("CommandLine"); + m_commandLine->setObjectName("CommandLine"); m_layout->addWidget(m_commandLine); m_layout->addWidget(m_emptyCanvas); @@ -602,7 +603,7 @@ namespace ScriptCanvasEditor // in sync with the order we display under tools for consistency. { const bool isInContextMenu = false; - Widget::ScriptCanvasNodePaletteConfig nodePaletteConfig(m_nodePaletteModel, m_scriptEventsAssetModel, isInContextMenu); + Widget::ScriptCanvasNodePaletteConfig nodePaletteConfig(m_nodePaletteModel, m_scriptEventsAssetModel, isInContextMenu); m_nodePalette = aznew Widget::NodePaletteDockWidget(tr("Node Palette"), this, nodePaletteConfig); m_nodePalette->setObjectName("NodePalette"); @@ -734,21 +735,23 @@ namespace ScriptCanvasEditor message.append(QObject::tr("
%1 graph(s) that need manual corrections. You will be prompted to review them after you close this dialog.
").arg(assetsThatNeedManualInspection)); } - // Report - char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 }; - AZStd::string outputFileName = AZStd::string::format("@devroot@/ScriptCanvasUpgradeReport.html"); - AZ::IO::FileIOBase::GetInstance()->ResolvePath(outputFileName.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); - AZStd::string urlToReport = AZStd::string::format("For more information see the Upgrade Report.", resolvedBuffer); + auto settingsRegistry = AZ::SettingsRegistry::Get(); + + AZ::IO::Path outputFileName; + settingsRegistry->Get(outputFileName.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectLogPath); + outputFileName /= "ScriptCanvasUpgradeReport.html"; + // Report + AZStd::string urlToReport = AZStd::string::format("For more information see the Upgrade Report.", outputFileName.c_str()); message.append(QObject::tr("
%1").arg(urlToReport.c_str())); // Backup if (upgradeTool->HasBackup()) { - AZStd::string outputFileName2 = AZStd::string::format("@devroot@/ScriptCanvas_BACKUP"); + AZ::IO::Path outputFileName2; + settingsRegistry->Get(outputFileName2.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectUserPath); + outputFileName2 /= "ScriptCanvas_BACKUP"; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(outputFileName2.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); - - AZStd::string backupPath = AZStd::string::format("
Open the Backup Folder.", resolvedBuffer); + AZStd::string backupPath = AZStd::string::format("
Open the Backup Folder.", outputFileName.c_str()); message.append(QObject::tr("%1").arg(backupPath.c_str())); } @@ -882,14 +885,14 @@ namespace ScriptCanvasEditor connect(ui->action_ViewVariableManager, &QAction::triggered, this, &MainWindow::OnVariableManager); connect(m_variableDockWidget, &QDockWidget::visibilityChanged, this, &MainWindow::OnViewVisibilityChanged); - + connect(ui->action_ViewLogWindow, &QAction::triggered, this, &MainWindow::OnViewLogWindow); connect(m_loggingWindow, &QDockWidget::visibilityChanged, this, &MainWindow::OnViewVisibilityChanged); connect(ui->action_ViewDebugger, &QAction::triggered, this, &MainWindow::OnViewDebugger); connect(ui->action_ViewCommandLine, &QAction::triggered, this, &MainWindow::OnViewCommandLine); connect(ui->action_ViewLog, &QAction::triggered, this, &MainWindow::OnViewLog); - + connect(ui->action_GraphValidation, &QAction::triggered, this, &MainWindow::OnViewGraphValidation); connect(ui->action_Debugging, &QAction::triggered, this, &MainWindow::OnViewDebuggingWindow); @@ -897,7 +900,7 @@ namespace ScriptCanvasEditor connect(ui->action_NodeStatistics, &QAction::triggered, this, &MainWindow::OnViewStatisticsPanel); connect(ui->action_PresetsEditor, &QAction::triggered, this, &MainWindow::OnViewPresetsEditor); - connect(ui->action_ViewRestoreDefaultLayout, &QAction::triggered, this, &MainWindow::OnRestoreDefaultLayout); + connect(ui->action_ViewRestoreDefaultLayout, &QAction::triggered, this, &MainWindow::OnRestoreDefaultLayout); } void MainWindow::SignalActiveSceneChanged(AZ::Data::AssetId assetId) @@ -920,7 +923,7 @@ namespace ScriptCanvasEditor // The paste action refreshes based on the scene's mimetype RefreshPasteAction(); - + bool enabled = false; if (graphId.IsValid()) @@ -1016,7 +1019,7 @@ namespace ScriptCanvasEditor QString tabName = m_tabBar->tabText(tabCounter); UnsavedChangesOptions shouldSaveResults = ShowSaveDialog(tabName); - + if (shouldSaveResults == UnsavedChangesOptions::SAVE) { Callbacks::OnSave saveCB = [this](bool isSuccessful, AZ::Data::AssetPtr, AZ::Data::AssetId) @@ -1041,7 +1044,7 @@ namespace ScriptCanvasEditor { m_processedClosedAssetIds.clear(); event->ignore(); - + return; } else if (shouldSaveResults == UnsavedChangesOptions::CONTINUE_WITHOUT_SAVING && @@ -1066,7 +1069,7 @@ namespace ScriptCanvasEditor } m_processedClosedAssetIds.clear(); - + event->accept(); } @@ -1232,7 +1235,7 @@ namespace ScriptCanvasEditor const Tracker::ScriptCanvasFileState& fileState = GetAssetFileState(memoryAssetId); if (fileState != Tracker::ScriptCanvasFileState::NEW) { - AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::UpdateFileState, memoryAssetId, Tracker::ScriptCanvasFileState::MODIFIED); + AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::UpdateFileState, memoryAssetId, Tracker::ScriptCanvasFileState::MODIFIED); } } } @@ -1734,12 +1737,12 @@ namespace ScriptCanvasEditor { currentTarget.SetInvalid(); } - } + } } return retVal; } - + void MainWindow::OnFileNew() { MakeNewFile(); @@ -1756,7 +1759,7 @@ namespace ScriptCanvasEditor m_tabBar->InsertGraphTab(tabIndex, assetId); if (!IsTabOpen(assetId, outTabIndex)) - { + { AZ_Assert(false, AZStd::string::format("Unable to open new Script Canvas Asset with id %s in the Script Canvas Editor", AssetHelpers::AssetIdToString(assetId).c_str()).c_str()); return -1; } @@ -1854,7 +1857,7 @@ namespace ScriptCanvasEditor } PrepareAssetForSave(inMemoryAssetId); - + AZStd::string suggestedFilename; AZStd::string suggestedFileFilter; GetSuggestedFullFilenameToSaveAs(inMemoryAssetId, suggestedFilename, suggestedFileFilter); @@ -1881,7 +1884,7 @@ namespace ScriptCanvasEditor AZStd::string assetRoot; AZStd::array assetRootChar; - AZ::IO::FileIOBase::GetInstance()->ResolvePath("@devroot@", assetRootChar.data(), assetRootChar.size()); + AZ::IO::FileIOBase::GetInstance()->ResolvePath("@engroot@", assetRootChar.data(), assetRootChar.size()); assetRoot = assetRootChar.data(); /* if (!AZ::StringFunc::StartsWith(filePath, assetRoot)) @@ -1906,7 +1909,7 @@ namespace ScriptCanvasEditor if (isValidFileName) { - AZStd::string internalStringFile = selectedFile.toUtf8().data(); + AZStd::string internalStringFile = selectedFile.toUtf8().data(); if (!AssetHelpers::IsValidSourceFile(internalStringFile, GetActiveScriptCanvasId())) { @@ -1923,7 +1926,7 @@ namespace ScriptCanvasEditor return true; } - + return false; } @@ -1965,7 +1968,7 @@ namespace ScriptCanvasEditor saveTabIndex = m_tabBar->FindTab(previousFileAssetId); } } - + AzFramework::StringFunc::Path::GetFileName(memoryAsset->GetAbsolutePath().c_str(), tabName); // Update the tab's assetId to the file asset Id (necessary when saving a new asset) @@ -2047,7 +2050,7 @@ namespace ScriptCanvasEditor } m_closeCurrentGraphAfterSave = false; - + EnableAssetView(memoryAsset); UnblockCloseRequests(); @@ -2071,7 +2074,7 @@ namespace ScriptCanvasEditor AZStd::invoke(onSave, saveSuccess, asset, previousAssetId); } }; - + AssetTrackerRequestBus::Broadcast(&AssetTrackerRequests::Save, assetId, onSaveCallback); UpdateSaveState(); @@ -2109,7 +2112,7 @@ namespace ScriptCanvasEditor // Disable the current view if we are saving. if (memoryAsset) { - DisableAssetView(memoryAsset); + DisableAssetView(memoryAsset); } BlockCloseRequests(); @@ -2126,7 +2129,7 @@ namespace ScriptCanvasEditor AZStd::string assetRoot; { AZStd::array assetRootChar; - AZ::IO::FileIOBase::GetInstance()->ResolvePath("@devassets@", assetRootChar.data(), assetRootChar.size()); + AZ::IO::FileIOBase::GetInstance()->ResolvePath("@projectroot@", assetRootChar.data(), assetRootChar.size()); assetRoot = assetRootChar.data(); } @@ -2147,7 +2150,7 @@ namespace ScriptCanvasEditor AssetRegistryRequestBus::BroadcastResult(fileFilters, &AssetRegistryRequests::GetAssetHandlerFileFilters); QString filter; - + AZStd::set filterSet; auto aggregateFilters = fileFilters.values; for (auto aggregateFilters2 : fileFilters.values) @@ -2190,7 +2193,7 @@ namespace ScriptCanvasEditor dialog.setFileMode(QFileDialog::ExistingFiles); dialog.setNameFilters(nameFilters); - if (dialog.exec() == QDialog::Accepted) + if (dialog.exec() == QDialog::Accepted) { m_filesToOpen = dialog.selectedFiles(); @@ -2206,7 +2209,7 @@ namespace ScriptCanvasEditor ui->action_Paste->setShortcut(QKeySequence(QKeySequence::Paste)); ui->action_Delete->setShortcut(QKeySequence(QKeySequence::Delete)); - connect(ui->menuEdit, &QMenu::aboutToShow, this, &MainWindow::OnEditMenuShow); + connect(ui->menuEdit, &QMenu::aboutToShow, this, &MainWindow::OnEditMenuShow); // Edit Menu connect(ui->action_Undo, &QAction::triggered, this, &MainWindow::TriggerUndo); @@ -2215,8 +2218,8 @@ namespace ScriptCanvasEditor connect(ui->action_Copy, &QAction::triggered, this, &MainWindow::OnEditCopy); connect(ui->action_Paste, &QAction::triggered, this, &MainWindow::OnEditPaste); connect(ui->action_Duplicate, &QAction::triggered, this, &MainWindow::OnEditDuplicate); - connect(ui->action_Delete, &QAction::triggered, this, &MainWindow::OnEditDelete); - connect(QApplication::clipboard(), &QClipboard::dataChanged, this, &MainWindow::RefreshPasteAction); + connect(ui->action_Delete, &QAction::triggered, this, &MainWindow::OnEditDelete); + connect(QApplication::clipboard(), &QClipboard::dataChanged, this, &MainWindow::RefreshPasteAction); connect(ui->action_RemoveUnusedNodes, &QAction::triggered, this, &MainWindow::OnRemoveUnusedNodes); connect(ui->action_RemoveUnusedVariables, &QAction::triggered, this, &MainWindow::OnRemoveUnusedVariables); connect(ui->action_RemoveUnusedElements, &QAction::triggered, this, &MainWindow::OnRemoveUnusedElements); @@ -2246,7 +2249,7 @@ namespace ScriptCanvasEditor connect(ui->action_GotoEndOfChain, &QAction::triggered, this, &MainWindow::OnGotoEndOfChain); - connect(ui->action_GlobalPreferences, &QAction::triggered, [this]() + connect(ui->action_GlobalPreferences, &QAction::triggered, [this]() { ScriptCanvasEditor::SettingsDialog(ui->action_GlobalPreferences->text(), ScriptCanvas::ScriptCanvasId(), this).exec(); @@ -2372,7 +2375,7 @@ namespace ScriptCanvasEditor { AZ::EntityId graphCanvasGraphId = GetActiveGraphCanvasGraphId(); - GraphCanvas::SceneRequestBus::Event(graphCanvasGraphId, &GraphCanvas::SceneRequests::SelectAllRelative, GraphCanvas::ConnectionType::CT_Input); + GraphCanvas::SceneRequestBus::Event(graphCanvasGraphId, &GraphCanvas::SceneRequests::SelectAllRelative, GraphCanvas::ConnectionType::CT_Input); } void MainWindow::OnSelectOutputs() @@ -2635,8 +2638,8 @@ namespace ScriptCanvasEditor { ScriptCanvas::ScriptCanvasId scriptCanvasId; AssetTrackerRequestBus::BroadcastResult(scriptCanvasId, &AssetTrackerRequests::GetScriptCanvasId, assetId); - return scriptCanvasId; - } + return scriptCanvasId; + } ScriptCanvas::ScriptCanvasId MainWindow::GetScriptCanvasId(const GraphCanvas::GraphId& graphCanvasGraphId) const { @@ -2849,7 +2852,7 @@ namespace ScriptCanvasEditor AssetTrackerRequests::AssetList assets; AssetTrackerRequestBus::BroadcastResult(assets, &AssetTrackerRequests::GetAssets); - + for (auto asset : assets) { RemoveScriptCanvasAsset(asset->GetAsset().GetId()); @@ -2927,14 +2930,14 @@ namespace ScriptCanvasEditor } void MainWindow::SaveTab(int index) - { + { QVariant tabdata = m_tabBar->tabData(index); if (tabdata.isValid()) { auto assetId = tabdata.value(); SaveAssetImpl(assetId, nullptr); } - + } void MainWindow::CloseAllTabs() @@ -2955,7 +2958,7 @@ namespace ScriptCanvasEditor m_isClosingTabs = true; m_skipTabOnClose = assetId; CloseNextTab(); - } + } } void MainWindow::CopyPathToClipboard(int index) @@ -3051,7 +3054,7 @@ namespace ScriptCanvasEditor // The last tab has been removed. SetActiveAsset({}); } - + // Handling various close all events because the save is async need to deal with this in a bunch of different ways // Always want to trigger this, even if we don't have any active tabs to avoid doubling the clean-up // information @@ -3069,7 +3072,7 @@ namespace ScriptCanvasEditor for (const auto& slotId : outputDataSlotIds) { - + if (!IsInUndoRedo(graphCanvasGraphId) && !isPaste && CreateAzEventHandlerSlotMenuAction::FindBehaviorMethodWithAzEventReturn(graphCanvasGraphId, slotId)) { CreateAzEventHandlerSlotMenuAction eventHandlerAction(this); @@ -3195,7 +3198,7 @@ namespace ScriptCanvasEditor m_minimap->hide(); } */ - + resizeDocks( { m_nodePalette, m_propertyGrid }, { static_cast(size().width() * 0.15f), static_cast(size().width() * 0.2f) }, @@ -3204,7 +3207,7 @@ namespace ScriptCanvasEditor resizeDocks({ m_nodePalette, m_minimap }, { static_cast(size().height() * 0.70f), static_cast(size().height() * 0.30f) }, Qt::Vertical); - + resizeDocks({ m_propertyGrid, m_variableDockWidget }, { static_cast(size().height() * 0.70f), static_cast(size().height() * 0.30f) }, @@ -3229,7 +3232,7 @@ namespace ScriptCanvasEditor AZ::EntityId graphCanvasGraphId; EditorGraphRequestBus::EventResult(graphCanvasGraphId, scriptCanvasId, &EditorGraphRequests::GetGraphCanvasGraphId); - + bool hasCopiableSelection = false; bool hasSelection = false; @@ -3268,7 +3271,7 @@ namespace ScriptCanvasEditor ui->action_Duplicate->setEnabled(hasCopiableSelection); // Delete will work for anything that is selectable - ui->action_Delete->setEnabled(hasSelection); + ui->action_Delete->setEnabled(hasSelection); } void MainWindow::OnViewNodePalette() @@ -3470,7 +3473,7 @@ namespace ScriptCanvasEditor if (ui->action_Debugging->isChecked() != m_loggingWindow->isVisible()) { ui->action_Debugging->setChecked(m_loggingWindow->isVisible()); - } + } // Want these two elements to be mutually exclusive. if (m_statusWidget->isVisible() == m_validationDockWidget->isVisible()) @@ -3624,7 +3627,7 @@ namespace ScriptCanvasEditor if (m_isRestoringWorkspace) { m_isRestoringWorkspace = false; - + if (m_queuedFocusOverride.IsValid()) { SetActiveAsset(m_queuedFocusOverride); @@ -3701,7 +3704,7 @@ namespace ScriptCanvasEditor hasModifications = ( fileState == Tracker::ScriptCanvasFileState::MODIFIED || fileState == Tracker::ScriptCanvasFileState::NEW || fileState == Tracker::ScriptCanvasFileState::SOURCE_REMOVED); - + AssetTrackerRequestBus::BroadcastResult(isSaving, &AssetTrackerRequests::IsSaving, m_activeAssetId); } @@ -4084,7 +4087,7 @@ namespace ScriptCanvasEditor if (action == nullptr) { GraphCanvas::GraphCanvasMimeEvent* mimeEvent = m_sceneContextMenu->GetNodePalette()->GetContextMenuEvent(); - + NodeIdPair finalNode = ProcessCreateNodeMimeEvent(mimeEvent, graphCanvasGraphId, AZ::Vector2(aznumeric_cast(scenePoint.x()), aznumeric_cast(scenePoint.y()))); GraphCanvas::SceneRequestBus::Event(graphCanvasGraphId, &GraphCanvas::SceneRequests::ClearSelection); @@ -4436,7 +4439,7 @@ namespace ScriptCanvasEditor targetLayer = (*selectedEntityIdIter); - selectedEntityIdIter = selectedEntityIds.erase(selectedEntityIdIter); + selectedEntityIdIter = selectedEntityIds.erase(selectedEntityIdIter); } else { @@ -4456,7 +4459,7 @@ namespace ScriptCanvasEditor AZ::TransformBus::Event(createdId, &AZ::TransformBus::Events::SetParent, targetLayer); } } - + for (const AZ::EntityId& entityId : selectedEntityIds) { AssignGraphToEntityImpl(entityId); @@ -4515,7 +4518,7 @@ namespace ScriptCanvasEditor { usableRequestBus = firstRequestBus; } - + if (usableRequestBus == nullptr) { AzToolsFramework::EntityCompositionRequestBus::Broadcast(&EntityCompositionRequests::AddComponentsToEntities, AzToolsFramework::EntityIdList{ entityId } @@ -4681,7 +4684,7 @@ namespace ScriptCanvasEditor } bool MainWindow::IsNodeNudgingEnabled() const - { + { if (m_userSettings) { return m_userSettings->m_allowNodeNudging; @@ -4720,7 +4723,7 @@ namespace ScriptCanvasEditor return 0.03f; } - float MainWindow::GetShakeDeadZonePercent() const + float MainWindow::GetShakeDeadZonePercent() const { if (m_userSettings) { @@ -4730,7 +4733,7 @@ namespace ScriptCanvasEditor return 0.01f; } - float MainWindow::GetShakeStraightnessPercent() const + float MainWindow::GetShakeStraightnessPercent() const { if (m_userSettings) { diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h index ba5ff7f97f..30e84f3fa8 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/MainWindow.h @@ -673,7 +673,7 @@ namespace ScriptCanvasEditor AZStd::array assetRootArray; if (!AZ::IO::FileIOBase::GetInstance()->ResolvePath(ScriptCanvas::AssetDescription::GetSuggestedSavePath(), assetRootArray.data(), assetRootArray.size())) { - AZ_ErrorOnce("Script Canvas", false, "Unable to resolve @devassets@ path"); + AZ_ErrorOnce("Script Canvas", false, "Unable to resolve @projectroot@ path"); } AZStd::string assetPath; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.cpp index 5e6858c993..f1832927c5 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.cpp @@ -13,7 +13,9 @@ #include #include +#include #include +#include #include #include @@ -169,10 +171,11 @@ namespace ScriptCanvasEditor QDateTime theTime = QDateTime::currentDateTime(); QString subFolder = theTime.toString("yyyy-MM-dd [HH.mm.ss]"); - m_backupPath = AZStd::string::format("@devroot@/ScriptCanvas_BACKUP/%s", subFolder.toUtf8().data()); - char backupPathCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(m_backupPath.c_str(), backupPathCStr, AZ_MAX_PATH_LEN); - m_backupPath = backupPathCStr; + auto settingsRegistry = AZ::SettingsRegistry::Get(); + m_backupPath.clear(); + settingsRegistry->Get(m_backupPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectUserPath); + + m_backupPath = m_backupPath / "ScriptCanvas_BACKUP" / subFolder.toUtf8().data(); if (!AZ::IO::FileIOBase::GetInstance()->Exists(m_backupPath.c_str())) { @@ -489,56 +492,25 @@ namespace ScriptCanvasEditor void UpgradeTool::BackupAsset(const AZ::Data::AssetInfo& assetInfo) { - - AZStd::string devRoot = "@devroot@"; - AZStd::string devAssets = "@devassets@"; - - char devRootCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(devRoot.c_str(), devRootCStr, AZ_MAX_PATH_LEN); - - char devAssetsCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(devAssets.c_str(), devAssetsCStr, AZ_MAX_PATH_LEN); - - AZStd::string relativePath = devAssetsCStr; - AzFramework::StringFunc::Replace(relativePath, devRootCStr, ""); - if (relativePath.starts_with("/")) - { - relativePath = relativePath.substr(1, relativePath.size() - 1); - } - - AZStd::string sourceFilePath; + AZ::IO::FixedMaxPath sourceFilePath; // Using this to get the watch folder AZStd::string watchFolder; - AZ::Data::AssetInfo assetInfo2; + AZ::Data::AssetInfo sourceFileAssetInfo; bool sourceInfoFound{}; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, assetInfo.m_relativePath.c_str(), assetInfo2, watchFolder); + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(sourceInfoFound, + &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, + assetInfo.m_relativePath.c_str(), sourceFileAssetInfo, watchFolder); if (sourceInfoFound) { - AZStd::string assetPath; - AzFramework::StringFunc::Path::Join(watchFolder.c_str(), assetInfo.m_relativePath.c_str(), assetPath); - - sourceFilePath = assetPath; + sourceFilePath = AZ::IO::FixedMaxPath(AZStd::string_view(watchFolder)) / sourceFileAssetInfo.m_relativePath; } - devRoot = devRootCStr; - AzFramework::StringFunc::Path::Normalize(devRoot); - - relativePath = sourceFilePath; - AzFramework::StringFunc::Replace(relativePath, devRoot.c_str(), ""); - if (relativePath.starts_with("/")) - { - relativePath = relativePath.substr(1, relativePath.size() - 1); - } - - AZStd::string targetFilePath; - AzFramework::StringFunc::Path::Join(m_backupPath.c_str(), relativePath.c_str(), targetFilePath); + const auto targetFilePath = m_backupPath / sourceFileAssetInfo.m_relativePath; if (AZ::IO::FileIOBase::GetInstance()->Copy(sourceFilePath.c_str(), targetFilePath.c_str()) != AZ::IO::ResultCode::Error) { - AZStd::string filename; - AzFramework::StringFunc::Path::GetFileName(sourceFilePath.c_str(), filename); - AZ_TracePrintf("Script Canvas", "Backup: %s -> %s\n", filename.c_str(), targetFilePath.c_str()); + AZ_TracePrintf("Script Canvas", "Backup: %s -> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); } else { @@ -583,7 +555,7 @@ namespace ScriptCanvasEditor void UpgradeTool::SaveLog() { - AZStd::string outputFileName = AZStd::string::format("@devroot@/ScriptCanvasUpgradeReport.html"); + AZStd::string outputFileName = AZStd::string::format("@log@/ScriptCanvasUpgradeReport.html"); char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 }; AZ::IO::FileIOBase::GetInstance()->ResolvePath(outputFileName.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.h b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.h index be00198457..8a2034bf4f 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeTool.h @@ -27,6 +27,7 @@ AZ_POP_DISABLE_WARNING #include #include #include +#include #endif class QPushButton; @@ -135,7 +136,7 @@ namespace ScriptCanvasEditor AZ::Entity* m_scriptCanvasEntity = nullptr; - AZStd::string m_backupPath; + AZ::IO::Path m_backupPath; void FinalizeUpgrade(); void DisconnectBuses(); diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorer.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorer.cpp index eb182ed291..f400f84d51 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorer.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/VersionExplorer.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -301,51 +302,37 @@ namespace ScriptCanvasEditor return ""; } + auto fileIoBase = AZ::IO::FileIOBase::GetInstance(); + auto settingsRegistry = AZ::SettingsRegistry::Get(); + QDateTime theTime = QDateTime::currentDateTime(); QString subFolder = theTime.toString("yyyy-MM-dd [HH.mm.ss]"); - AZStd::string backupPath = AZStd::string::format("@devroot@/ScriptCanvas_BACKUP/%s", subFolder.toUtf8().data()); - char backupPathCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(backupPath.c_str(), backupPathCStr, AZ_MAX_PATH_LEN); - backupPath = backupPathCStr; + AZ::IO::FixedMaxPath projectUserPath; + settingsRegistry->Get(projectUserPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectUserPath); - if (!AZ::IO::FileIOBase::GetInstance()->Exists(backupPath.c_str())) + AZ::IO::FixedMaxPath backupPath = projectUserPath / "ScriptCanvas_BACKUP" / subFolder.toUtf8().data(); + + if (!fileIoBase->Exists(backupPath.c_str())) { - if (AZ::IO::FileIOBase::GetInstance()->CreatePath(backupPath.c_str()) != AZ::IO::ResultCode::Success) + if (fileIoBase->CreatePath(backupPath.c_str()) != AZ::IO::ResultCode::Success) { AZ_Error(ScriptCanvas::k_VersionExplorerWindow.data(), false, "Failed to create backup folder %s", backupPath.c_str()); return "Failed to create backup folder"; } } - AZStd::string devRoot = "@devroot@"; - AZStd::string devAssets = "@devassets@"; - - char devRootCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(devRoot.c_str(), devRootCStr, AZ_MAX_PATH_LEN); - - char devAssetsCStr[AZ_MAX_PATH_LEN] = { 0 }; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(devAssets.c_str(), devAssetsCStr, AZ_MAX_PATH_LEN); - - AZStd::string relativePath = devAssetsCStr; - AzFramework::StringFunc::Replace(relativePath, devRootCStr, ""); - if (relativePath.starts_with("/")) - { - relativePath = relativePath.substr(1, relativePath.size() - 1); - } - - AZStd::string sourceFilePath; - AZStd::string watchFolder; AZ::Data::AssetInfo assetInfo; + + AZ::IO::FixedMaxPath sourceFilePath; bool sourceInfoFound{}; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, asset.GetHint().c_str(), assetInfo, watchFolder); + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(sourceInfoFound, + &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, + asset.GetHint().c_str(), assetInfo, watchFolder); if (sourceInfoFound) { - AZStd::string assetPath; - AzFramework::StringFunc::Path::Join(watchFolder.c_str(), assetInfo.m_relativePath.c_str(), assetPath); - - sourceFilePath = assetPath; + sourceFilePath = AZ::IO::FixedMaxPath(AZStd::string_view(watchFolder)) / assetInfo.m_relativePath; } else { @@ -353,23 +340,9 @@ namespace ScriptCanvasEditor return "Failed to find source file"; } - devRoot = devRootCStr; - AzFramework::StringFunc::Path::Normalize(devRoot); + const AZ::IO::FixedMaxPath targetFilePath = backupPath / assetInfo.m_relativePath; - relativePath = sourceFilePath; - AzFramework::StringFunc::Replace(relativePath, devRoot.c_str(), ""); - if (relativePath.starts_with("/")) - { - relativePath = relativePath.substr(1, relativePath.size() - 1); - } - - AzFramework::StringFunc::Path::Normalize(relativePath); - AzFramework::StringFunc::Path::Normalize(backupPath); - - AZStd::string targetFilePath = backupPath; - targetFilePath += relativePath; - - if (AZ::IO::FileIOBase::GetInstance()->Copy(sourceFilePath.c_str(), targetFilePath.c_str()) != AZ::IO::ResultCode::Success) + if (fileIoBase->Copy(sourceFilePath.c_str(), targetFilePath.c_str()) != AZ::IO::ResultCode::Success) { AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "VersionExplorer::BackupGraph: Error creating backup: %s ---> %s\n", sourceFilePath.c_str(), targetFilePath.c_str()); return "Failed to copy source file to backup location"; @@ -602,7 +575,7 @@ namespace ScriptCanvasEditor }); streamer->QueueRequest(flushRequest); } - } + } } void VersionExplorer::GraphUpgradeComplete @@ -816,7 +789,7 @@ namespace ScriptCanvasEditor } char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 }; - AZStd::string path = AZStd::string::format("@devroot@/%s", asset.GetHint().c_str()); + AZStd::string path = AZStd::string::format("@engroot@/%s", asset.GetHint().c_str()); AZ::IO::FileIOBase::GetInstance()->ResolvePath(path.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN); AZ::StringFunc::Path::GetFullPath(resolvedBuffer, path); AZ::StringFunc::Path::Normalize(path); @@ -873,7 +846,7 @@ namespace ScriptCanvasEditor m_state = ProcessState::Upgrade; AZ::SystemTickBus::Handler::BusConnect(); - } + } } } @@ -883,7 +856,7 @@ namespace ScriptCanvasEditor m_inProgress = false; m_ui->progressBar->setValue(aznumeric_cast(m_currentAssetRowIndex)); m_ui->scanButton->setEnabled(true); - + m_inspectingAsset = m_assetsToInspect.erase(m_inspectingAsset); FlushLogs(); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/ExecutionLogAsset.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/ExecutionLogAsset.cpp index 51cb034f35..e1fe71d4d9 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/ExecutionLogAsset.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/ExecutionLogAsset.cpp @@ -85,7 +85,7 @@ namespace ScriptCanvas const char* ExecutionLogAsset::GetDefaultDirectoryRoot() { - return AZ::IO::FileIOBase::GetInstance()->GetAlias("@devroot@"); + return AZ::IO::FileIOBase::GetInstance()->GetAlias("@engroot@"); } ExecutionLogAsset::ExecutionLogAsset(const AZ::Data::AssetId& assetId, AZ::Data::AssetData::AssetStatus status) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.h index 037985d980..24c83b20a1 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.h @@ -36,7 +36,7 @@ namespace ScriptCanvas azrtti_typeid(), "Script Canvas Runtime", "Script Canvas Runtime Graph", - "@devassets@/scriptcanvas", + "@projectroot@/scriptcanvas", ".scriptcanvas_compiled", "Script Canvas Runtime", "Untitled-%i", @@ -177,7 +177,7 @@ namespace ScriptCanvas azrtti_typeid(), "Script Canvas Function Interface", "Script Canvas Function Interface", - "@devassets@/scriptcanvas", + "@projectroot@/scriptcanvas", ".scriptcanvas_fn_compiled", "Script Canvas Function Interface", "Untitled-Function-%i", diff --git a/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp b/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp index 849e2272a2..ee0052d5b9 100644 --- a/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp +++ b/Gems/WhiteBox/Code/Source/EditorWhiteBoxComponent.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -129,7 +130,7 @@ namespace WhiteBox AzToolsFramework::EditorPythonRunnerRequestBus::Broadcast( &AzToolsFramework::EditorPythonRunnerRequestBus::Events::ExecuteByFilenameWithArgs, - "@devroot@/Gems/WhiteBox/Editor/Scripts/default_shapes.py", scriptArgs); + "@engroot@/Gems/WhiteBox/Editor/Scripts/default_shapes.py", scriptArgs); EditorWhiteBoxComponentNotificationBus::Event( AZ::EntityComponentIdPair(GetEntityId(), GetId()), @@ -499,13 +500,13 @@ namespace WhiteBox static AZStd::string WhiteBoxPathAtProjectRoot(const AZStd::string_view name, const AZStd::string_view extension) { - const char* projectFolder = nullptr; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult( - projectFolder, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetAbsoluteDevGameFolderPath); - - return AZStd::string::format( - "%s\\%.*s_whitebox.%.*s", projectFolder, aznumeric_cast(name.size()), name.data(), - aznumeric_cast(extension.size()), extension.data()); + AZ::IO::Path whiteBoxPath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + settingsRegistry->Get(whiteBoxPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath); + } + whiteBoxPath /= AZ::IO::FixedMaxPathString::format("%.*s.%.*s", AZ_STRING_ARG(name), AZ_STRING_ARG(extension)); + return whiteBoxPath.Native(); } void EditorWhiteBoxComponent::ExportToFile() diff --git a/Registry/fileio.setreg b/Registry/fileio.setreg new file mode 100644 index 0000000000..d89e9f3f89 --- /dev/null +++ b/Registry/fileio.setreg @@ -0,0 +1,26 @@ +{ + "O3DE": { + "AzCore": { + "FileIO": { + "DeprecatedAliases": [ + { + "OldAlias": "@assets@", + "NewAlias": "@products@" + }, + { + "OldAlias": "@root@", + "NewAlias": "@products@" + }, + { + "OldAlias": "@devassets@", + "NewAlias": "@projectroot@" + }, + { + "OldAlias": "@devroot@", + "NewAlias": "@engroot@" + } + ] + } + } + } +} From e5a7315de439efbc58b65d8ad544a1b32fbe52f3 Mon Sep 17 00:00:00 2001 From: bosnichd Date: Tue, 5 Oct 2021 14:59:50 -0600 Subject: [PATCH 25/27] Auto-expand input mappings. (#4501) Signed-off-by: bosnichd --- .../AzFramework/AzFramework/Input/Mappings/InputMappingAnd.cpp | 1 + .../AzFramework/AzFramework/Input/Mappings/InputMappingOr.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/Code/Framework/AzFramework/AzFramework/Input/Mappings/InputMappingAnd.cpp b/Code/Framework/AzFramework/AzFramework/Input/Mappings/InputMappingAnd.cpp index 6837807f4e..a24860fd34 100644 --- a/Code/Framework/AzFramework/AzFramework/Input/Mappings/InputMappingAnd.cpp +++ b/Code/Framework/AzFramework/AzFramework/Input/Mappings/InputMappingAnd.cpp @@ -35,6 +35,7 @@ namespace AzFramework ->Attribute(AZ::Edit::Attributes::NameLabelOverride, &InputMappingAnd::Config::GetNameLabelOverride) ->DataElement(AZ::Edit::UIHandlers::Default, &Config::m_sourceInputChannelNames, "Source Input Channel Names", "The source input channel names that will be mapped to the output input channel name.") + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ; } } diff --git a/Code/Framework/AzFramework/AzFramework/Input/Mappings/InputMappingOr.cpp b/Code/Framework/AzFramework/AzFramework/Input/Mappings/InputMappingOr.cpp index bc47065c05..7c983766c8 100644 --- a/Code/Framework/AzFramework/AzFramework/Input/Mappings/InputMappingOr.cpp +++ b/Code/Framework/AzFramework/AzFramework/Input/Mappings/InputMappingOr.cpp @@ -35,6 +35,7 @@ namespace AzFramework ->Attribute(AZ::Edit::Attributes::NameLabelOverride, &InputMappingOr::Config::GetNameLabelOverride) ->DataElement(AZ::Edit::UIHandlers::Default, &Config::m_sourceInputChannelNames, "Source Input Channel Names", "The source input channel names that will be mapped to the output input channel name.") + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ; } } From 84f28033a052553ebf69ca91d4efabff6d33f367 Mon Sep 17 00:00:00 2001 From: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> Date: Tue, 5 Oct 2021 14:43:30 -0700 Subject: [PATCH 26/27] ATOM-16249 Adding draw srg caching to DynamicDrawContext since creating SRG can be expensive for some backend (#4491) * ATOM-16249 Adding draw srg caching to DynamicDrawContext since creating SRG can be expensive for some backend Signed-off-by: Qing Tao --- .../Atom/RHI/ShaderResourceGroupData.h | 4 +++ .../Source/RHI/ShaderResourceGroupData.cpp | 8 ++++++ .../DynamicDraw/DynamicDrawContext.h | 2 ++ .../RPI.Public/Shader/ShaderResourceGroup.h | 3 ++ .../DynamicDraw/DynamicDrawContext.cpp | 28 +++++++++++++++---- .../RPI.Public/Shader/ShaderResourceGroup.cpp | 5 ++++ 6 files changed, 45 insertions(+), 5 deletions(-) diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/ShaderResourceGroupData.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/ShaderResourceGroupData.h index 0ce43159f6..cbb0db53c8 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/ShaderResourceGroupData.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/ShaderResourceGroupData.h @@ -166,6 +166,10 @@ namespace AZ AZStd::array_view> GetImageGroup() const; AZStd::array_view> GetBufferGroup() const; AZStd::array_view GetSamplerGroup() const; + + //! Reset image and buffer views setup for this ShaderResourceGroupData + //! So it won't hold references for any RHI resources + void ResetViews(); //! Returns the opaque constant data populated by calls to SetConstant and SetConstantData. //! diff --git a/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupData.cpp b/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupData.cpp index da7697d8f2..18b292ac64 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupData.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupData.cpp @@ -330,6 +330,14 @@ namespace AZ return m_samplers; } + void ShaderResourceGroupData::ResetViews() + { + m_imageViews.assign(m_imageViews.size(), nullptr); + m_bufferViews.assign(m_bufferViews.size(), nullptr); + m_imageViewsUnboundedArray.assign(m_imageViewsUnboundedArray.size(), nullptr); + m_bufferViewsUnboundedArray.assign(m_bufferViewsUnboundedArray.size(), nullptr); + } + AZStd::array_view ShaderResourceGroupData::GetConstantData() const { return m_constantsData.GetConstantData(); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/DynamicDraw/DynamicDrawContext.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/DynamicDraw/DynamicDrawContext.h index 93e595243e..c35d0750a5 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/DynamicDraw/DynamicDrawContext.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/DynamicDraw/DynamicDrawContext.h @@ -268,6 +268,8 @@ namespace AZ AZStd::vector m_cachedStreamBufferViews; AZStd::vector m_cachedIndexBufferViews; AZStd::vector> m_cachedDrawSrg; + + uint32_t m_nextDrawSrgIdx = 0; // structure includes DrawItem and stream and index buffer index using BufferViewIndexType = uint32_t; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderResourceGroup.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderResourceGroup.h index b2cea448c1..99f1f5f598 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderResourceGroup.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderResourceGroup.h @@ -133,6 +133,9 @@ namespace AZ /// Returns an array of RPI buffers associated with the buffer shader input index. AZStd::array_view> GetBufferArray(RHI::ShaderInputNameIndex& inputIndex) const; AZStd::array_view> GetBufferArray(RHI::ShaderInputBufferIndex inputIndex) const; + + //! Reset image and buffer views so that it won't hold references for any RHI resources + void ResetViews(); ////////////////////////////////////////////////////////////////////////// // Methods for assignment / access of RHI Image types. diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/DynamicDraw/DynamicDrawContext.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/DynamicDraw/DynamicDrawContext.cpp index 4da85823b3..3b3473a2da 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/DynamicDraw/DynamicDrawContext.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/DynamicDraw/DynamicDrawContext.cpp @@ -518,7 +518,6 @@ namespace AZ if (drawSrg) { drawItem.m_uniqueShaderResourceGroup = drawSrg->GetRHIShaderResourceGroup(); - m_cachedDrawSrg.push_back(drawSrg); } // Set scissor per draw if scissor is enabled. @@ -608,7 +607,6 @@ namespace AZ if (drawSrg) { drawItem.m_uniqueShaderResourceGroup = drawSrg->GetRHIShaderResourceGroup(); - m_cachedDrawSrg.push_back(drawSrg); } // Set scissor per draw if scissor is enabled. @@ -635,7 +633,22 @@ namespace AZ { return nullptr; } - auto drawSrg = AZ::RPI::ShaderResourceGroup::Create(m_shader->GetAsset(), m_shader->GetSupervariantIndex(), m_drawSrgLayout->GetName()); + + Data::Instance drawSrg; + if (m_nextDrawSrgIdx == m_cachedDrawSrg.size()) + { + drawSrg = AZ::RPI::ShaderResourceGroup::Create(m_shader->GetAsset(), m_shader->GetSupervariantIndex(), m_drawSrgLayout->GetName()); + m_cachedDrawSrg.push_back(drawSrg); + } + else if (m_nextDrawSrgIdx < m_cachedDrawSrg.size()) + { + drawSrg = m_cachedDrawSrg[m_nextDrawSrgIdx]; + } + else + { + AZ_Assert(false, "Unexpected next draw srg index"); + } + m_nextDrawSrgIdx++; // Set fallback value for shader variant if draw srg contains constant for shader variant fallback if (m_hasShaderVariantKeyFallbackEntry) @@ -727,7 +740,7 @@ namespace AZ } for (auto& drawItemProperties : m_cachedDrawList) - { + { view->AddDrawItem(m_drawListTag, drawItemProperties); } } @@ -743,9 +756,14 @@ namespace AZ m_cachedDrawItems.clear(); m_cachedStreamBufferViews.clear(); m_cachedIndexBufferViews.clear(); - m_cachedDrawSrg.clear(); m_cachedDrawList.clear(); + m_nextDrawSrgIdx = 0; m_drawFinalized = false; + + for (auto srg:m_cachedDrawSrg) + { + srg->ResetViews(); + } } const RHI::PipelineState* DynamicDrawContext::GetCurrentPipelineState() diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderResourceGroup.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderResourceGroup.cpp index 499365a9a9..f95c6abfcd 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderResourceGroup.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderResourceGroup.cpp @@ -580,6 +580,11 @@ namespace AZ return {}; } + void ShaderResourceGroup::ResetViews() + { + m_data.ResetViews(); + } + const RHI::SamplerState& ShaderResourceGroup::GetSampler(RHI::ShaderInputNameIndex& inputIndex, uint32_t arrayIndex) const { inputIndex.ValidateOrFindSamplerIndex(GetLayout()); From 977d58e1a8f0a3b68a229191ef9c252814fc8538 Mon Sep 17 00:00:00 2001 From: Nicholas Lawson <70027408+lawsonamzn@users.noreply.github.com> Date: Tue, 5 Oct 2021 15:20:26 -0700 Subject: [PATCH 27/27] Update ZLIB min req osx ios and android to reasonable limits (#4473) This also updates the name of the zlib library to uppercase ZLIB which conforms to normal CMake standards . Signed-off-by: lawsonamzn <70027408+lawsonamzn@users.noreply.github.com> --- Code/Editor/CMakeLists.txt | 2 -- Code/Editor/Plugins/EditorCommon/CMakeLists.txt | 1 - Code/Framework/AzCore/CMakeLists.txt | 2 +- Code/Framework/AzFramework/CMakeLists.txt | 1 - Code/Framework/AzNetworking/CMakeLists.txt | 1 - Code/Legacy/CrySystem/CMakeLists.txt | 1 - cmake/3rdParty/BuiltInPackages.cmake | 11 ++++++++++- .../Platform/Android/BuiltInPackages_android.cmake | 2 +- .../Platform/Linux/BuiltInPackages_linux.cmake | 2 +- cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake | 2 +- .../Platform/Windows/BuiltInPackages_windows.cmake | 2 +- cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake | 2 +- 12 files changed, 16 insertions(+), 13 deletions(-) diff --git a/Code/Editor/CMakeLists.txt b/Code/Editor/CMakeLists.txt index 5884795413..2ea0aa1a74 100644 --- a/Code/Editor/CMakeLists.txt +++ b/Code/Editor/CMakeLists.txt @@ -33,7 +33,6 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE Legacy::CryCommon - 3rdParty::zlib PUBLIC 3rdParty::Qt::Core 3rdParty::Qt::Gui @@ -105,7 +104,6 @@ ly_add_target( 3rdParty::Qt::Concurrent 3rdParty::tiff 3rdParty::squish-ccr - 3rdParty::zlib 3rdParty::AWSNativeSDK::STS Legacy::CryCommon Legacy::EditorCommon diff --git a/Code/Editor/Plugins/EditorCommon/CMakeLists.txt b/Code/Editor/Plugins/EditorCommon/CMakeLists.txt index cd9f2e79c7..609482b581 100644 --- a/Code/Editor/Plugins/EditorCommon/CMakeLists.txt +++ b/Code/Editor/Plugins/EditorCommon/CMakeLists.txt @@ -39,7 +39,6 @@ ly_add_target( EDITOR_COMMON_IMPORTS BUILD_DEPENDENCIES PRIVATE - 3rdParty::zlib 3rdParty::Qt::Core 3rdParty::Qt::Widgets Legacy::CryCommon diff --git a/Code/Framework/AzCore/CMakeLists.txt b/Code/Framework/AzCore/CMakeLists.txt index 60c5f50594..96ed838ccc 100644 --- a/Code/Framework/AzCore/CMakeLists.txt +++ b/Code/Framework/AzCore/CMakeLists.txt @@ -39,7 +39,7 @@ ly_add_target( 3rdParty::Lua 3rdParty::RapidJSON 3rdParty::RapidXML - 3rdParty::zlib + 3rdParty::ZLIB 3rdParty::zstd 3rdParty::cityhash ${AZ_CORE_PIX_BUILD_DEPENDENCIES} diff --git a/Code/Framework/AzFramework/CMakeLists.txt b/Code/Framework/AzFramework/CMakeLists.txt index 59393d90a1..b22586162b 100644 --- a/Code/Framework/AzFramework/CMakeLists.txt +++ b/Code/Framework/AzFramework/CMakeLists.txt @@ -29,7 +29,6 @@ ly_add_target( AZ::AzCore PUBLIC AZ::GridMate - 3rdParty::zlib 3rdParty::zstd 3rdParty::lz4 ) diff --git a/Code/Framework/AzNetworking/CMakeLists.txt b/Code/Framework/AzNetworking/CMakeLists.txt index 7f9d856eb9..a0a3871201 100644 --- a/Code/Framework/AzNetworking/CMakeLists.txt +++ b/Code/Framework/AzNetworking/CMakeLists.txt @@ -25,7 +25,6 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE AZ::AzCore - 3rdParty::zlib 3rdParty::zstd 3rdParty::OpenSSL PUBLIC diff --git a/Code/Legacy/CrySystem/CMakeLists.txt b/Code/Legacy/CrySystem/CMakeLists.txt index 9e1cf92267..4c1f0d9b82 100644 --- a/Code/Legacy/CrySystem/CMakeLists.txt +++ b/Code/Legacy/CrySystem/CMakeLists.txt @@ -28,7 +28,6 @@ ly_add_target( 3rdParty::lz4 3rdParty::md5 3rdParty::tiff - 3rdParty::zlib 3rdParty::zstd Legacy::CryCommon Legacy::CrySystem.XMLBinary diff --git a/cmake/3rdParty/BuiltInPackages.cmake b/cmake/3rdParty/BuiltInPackages.cmake index c583774e3a..743e2e983e 100644 --- a/cmake/3rdParty/BuiltInPackages.cmake +++ b/cmake/3rdParty/BuiltInPackages.cmake @@ -18,4 +18,13 @@ set(LY_PAL_PACKAGE_FILE_NAME ${CMAKE_CURRENT_LIST_DIR}/${pal_dir}/BuiltInPackage include(${LY_PAL_PACKAGE_FILE_NAME}) # add the above file to the ALLFILES list, so that they show up in IDEs -set(ALLFILES ${ALLFILES} ${LY_PAL_PACKAGE_FILE_NAME}) \ No newline at end of file +set(ALLFILES ${ALLFILES} ${LY_PAL_PACKAGE_FILE_NAME}) + +# temporary compatibility: +# Some 3p libraries may still refer to zlib as "3rdParty::zlib" instead of +# the correct "3rdParty::ZLIB" (Case difference). Until those libraries are updated +# we alias the casing here. This also provides backward compatibility for Gems that use 3rdParty::zlib +# that are not part of the core O3DE repo. +ly_download_associated_package(ZLIB) +find_package(ZLIB) +add_library(3rdParty::zlib ALIAS 3rdParty::ZLIB) diff --git a/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake b/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake index 5de2ad0253..4d17e4b20b 100644 --- a/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake +++ b/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake @@ -27,6 +27,6 @@ ly_associate_package(PACKAGE_NAME googlebenchmark-1.5.0-rev2-android TARGETS Goo ly_associate_package(PACKAGE_NAME libpng-1.6.37-rev1-android TARGETS libpng PACKAGE_HASH 51d3ec1559c5595196c11e11674cf5745989d3073bf33dabc6697e3eee77a1cc) ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-android TARGETS libsamplerate PACKAGE_HASH bf13662afe65d02bcfa16258a4caa9b875534978227d6f9f36c9cfa92b3fb12b) ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev1-android TARGETS OpenSSL PACKAGE_HASH 4036d4019d722f0e1b7a1621bf60b5a17ca6a65c9c78fd8701cee1131eec8480) -ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev2-android TARGETS zlib PACKAGE_HASH 85b730b97176772538cfcacd6b6aaf4655fc2d368d134d6dd55e02f28f183826) +ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev5-android TARGETS ZLIB PACKAGE_HASH 73c9e88892c237a3fc6eafc04268ccd9d479e6d55f9df2ed58b236c8f9cf2cae) ly_associate_package(PACKAGE_NAME lz4-1.9.3-vcpkg-rev4-android TARGETS lz4 PACKAGE_HASH f5b22642d218dbbb442cae61e469e5b241c4740acd258c3e8678e60dec61ea93) diff --git a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake index e634cb19c5..fb02a80088 100644 --- a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake +++ b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake @@ -42,7 +42,7 @@ ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev2-linux ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-1.6.2104-o3de-rev3-linux TARGETS DirectXShaderCompilerDxc PACKAGE_HASH 88c4a359325d749bc34090b9ac466424847f3b71ba0de15045cf355c17c07099) ly_associate_package(PACKAGE_NAME SPIRVCross-2021.04.29-rev1-linux TARGETS SPIRVCross PACKAGE_HASH 7889ee5460a688e9b910c0168b31445c0079d363affa07b25d4c8aeb608a0b80) ly_associate_package(PACKAGE_NAME azslc-1.7.23-rev2-linux TARGETS azslc PACKAGE_HASH 1ba84d8321a566d35a1e9aa7400211ba8e6d1c11c08e4be3c93e6e74b8f7aef1) -ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev2-linux TARGETS zlib PACKAGE_HASH 16f3b9e11cda525efb62144f354c1cfc30a5def9eff020dbe49cb00ee7d8234f) +ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev5-linux TARGETS ZLIB PACKAGE_HASH 9be5ea85722fc27a8645a9c8a812669d107c68e6baa2ca0740872eaeb6a8b0fc) ly_associate_package(PACKAGE_NAME squish-ccr-deb557d-rev1-linux TARGETS squish-ccr PACKAGE_HASH 85fecafbddc6a41a27c5f59ed4a5dfb123a94cb4666782cf26e63c0a4724c530) ly_associate_package(PACKAGE_NAME astc-encoder-3.2-rev1-linux TARGETS astc-encoder PACKAGE_HASH 2ba97a06474d609945f0ab4419af1f6bbffdd294ca6b869f5fcebec75c573c0f) ly_associate_package(PACKAGE_NAME ISPCTexComp-36b80aa-rev1-linux TARGETS ISPCTexComp PACKAGE_HASH 065fd12abe4247dde247330313763cf816c3375c221da030bdec35024947f259) diff --git a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake index fd46191015..e80956530a 100644 --- a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake +++ b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake @@ -40,7 +40,7 @@ ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev1-mac ly_associate_package(PACKAGE_NAME qt-5.15.2-rev5-mac TARGETS Qt PACKAGE_HASH 9d25918351898b308ded3e9e571fff6f26311b2071aeafd00dd5b249fdf53f7e) ly_associate_package(PACKAGE_NAME libpng-1.6.37-mac TARGETS libpng PACKAGE_HASH 1ad76cd038ccc1f288f83c5fe2859a0f35c5154e1fe7658e1230cc428d318a8b) ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-mac TARGETS libsamplerate PACKAGE_HASH b912af40c0ac197af9c43d85004395ba92a6a859a24b7eacd920fed5854a97fe) -ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev2-mac TARGETS zlib PACKAGE_HASH 21714e8a6de4f2523ee92a7f52d51fbee29c5f37ced334e00dc3c029115b472e) +ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev5-mac TARGETS ZLIB PACKAGE_HASH b6fea9c79b8bf106d4703b67fecaa133f832ad28696c2ceef45fb5f20013c096) ly_associate_package(PACKAGE_NAME squish-ccr-deb557d-rev1-mac TARGETS squish-ccr PACKAGE_HASH 155bfbfa17c19a9cd2ef025de14c5db598f4290045d5b0d83ab58cb345089a77) ly_associate_package(PACKAGE_NAME astc-encoder-3.2-rev1-mac TARGETS astc-encoder PACKAGE_HASH 96f6ea8c3e45ec7fe525230c7c53ca665c8300d8e28456cc19bb3159ce6f8dcc) ly_associate_package(PACKAGE_NAME ISPCTexComp-36b80aa-rev1-mac TARGETS ISPCTexComp PACKAGE_HASH 8a4e93277b8face6ea2fd57c6d017bdb55643ed3d6387110bc5f6b3b884dd169) diff --git a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake index 333c952051..7e112c405e 100644 --- a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake +++ b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake @@ -47,7 +47,7 @@ ly_associate_package(PACKAGE_NAME OpenMesh-8.1-rev1-windows ly_associate_package(PACKAGE_NAME civetweb-1.8-rev1-windows TARGETS civetweb PACKAGE_HASH 36d0e58a59bcdb4dd70493fb1b177aa0354c945b06c30416348fd326cf323dd4) ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev2-windows TARGETS OpenSSL PACKAGE_HASH 9af1c50343f89146b4053101a7aeb20513319a3fe2f007e356d7ce25f9241040) ly_associate_package(PACKAGE_NAME Crashpad-0.8.0-rev1-windows TARGETS Crashpad PACKAGE_HASH d162aa3070147bc0130a44caab02c5fe58606910252caf7f90472bd48d4e31e2) -ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev2-windows TARGETS zlib PACKAGE_HASH 9afab1d67641ed8bef2fb38fc53942da47f2ab339d9e77d3d20704a48af2da0b) +ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev5-windows TARGETS ZLIB PACKAGE_HASH 8847112429744eb11d92c44026fc5fc53caa4a06709382b5f13978f3c26c4cbd) ly_associate_package(PACKAGE_NAME squish-ccr-deb557d-rev1-windows TARGETS squish-ccr PACKAGE_HASH 5c3d9fa491e488ccaf802304ad23b932268a2b2846e383f088779962af2bfa84) ly_associate_package(PACKAGE_NAME astc-encoder-3.2-rev1-windows TARGETS astc-encoder PACKAGE_HASH 3addc6fc1a7eb0d6b7f3d530e962af967e6d92b3825ef485da243346357cf78e) ly_associate_package(PACKAGE_NAME ISPCTexComp-36b80aa-rev1-windows TARGETS ISPCTexComp PACKAGE_HASH b6fa6ea28a2808a9a5524c72c37789c525925e435770f2d94eb2d387360fa2d0) diff --git a/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake b/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake index 25df8101b4..c9de80c809 100644 --- a/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake +++ b/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake @@ -28,5 +28,5 @@ ly_associate_package(PACKAGE_NAME googlebenchmark-1.5.0-rev2-ios TARGETS GoogleB ly_associate_package(PACKAGE_NAME libpng-1.6.37-ios TARGETS libpng PACKAGE_HASH 18a8217721083c4dc46514105be43ca764fa9c994a74aa0b57766ea6f8187e7b) ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-ios TARGETS libsamplerate PACKAGE_HASH 7656b961697f490d4f9c35d2e61559f6fc38c32102e542a33c212cd618fc2119) ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev1-ios TARGETS OpenSSL PACKAGE_HASH cd0dfce3086a7172777c63dadbaf0ac3695b676119ecb6d0614b5fb1da03462f) -ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev2-ios TARGETS zlib PACKAGE_HASH a59fc0f83a02c616b679799310e9d86fde84514c6d2acefa12c6def0ae4a880c) +ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev5-ios TARGETS ZLIB PACKAGE_HASH c7f10b4d0fe63192054d926f53b08e852cdf472bc2b18e2f7be5aecac1869f7f) ly_associate_package(PACKAGE_NAME lz4-1.9.3-vcpkg-rev4-ios TARGETS lz4 PACKAGE_HASH 588ea05739caa9231a9a17a1e8cf64c5b9a265e16528bc05420af7e2534e86c1)