From e0d0bbfdaed37487b74cb02cd0156bd43b203347 Mon Sep 17 00:00:00 2001 From: kberg-amzn Date: Tue, 3 Aug 2021 13:12:37 -0700 Subject: [PATCH 01/70] Changes to desync debug output to make it less stressful on bandwidth and the server, as well as some fixes to corrections on the local client Signed-off-by: kberg-amzn --- .../Serialization/StringifySerializer.cpp | 18 +- .../Serialization/StringifySerializer.h | 12 +- Gems/Multiplayer/Code/CMakeLists.txt | 2 +- .../LocalPredictionPlayerInputComponent.h | 13 +- .../Multiplayer/Components/NetBindComponent.h | 19 +- .../Multiplayer/NetworkTime/INetworkTime.h | 5 + .../NetworkTime/RewindableObject.inl | 2 +- ...tionPlayerInputComponent.AutoComponent.xml | 1 - .../LocalPredictionPlayerInputComponent.cpp | 176 ++++++++---------- .../Source/Components/NetBindComponent.cpp | 15 ++ .../Source/MultiplayerSystemComponent.cpp | 4 +- .../EntityReplicationManager.cpp | 14 +- .../EntityReplicationManager.h | 1 + .../Code/Source/NetworkTime/NetworkTime.cpp | 9 + .../Code/Source/NetworkTime/NetworkTime.h | 1 + 15 files changed, 154 insertions(+), 138 deletions(-) diff --git a/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.cpp b/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.cpp index b35b01d45c..df018cb6ce 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.cpp @@ -23,9 +23,9 @@ namespace AzNetworking return m_string; } - const StringifySerializer::StringMap& StringifySerializer::GetValueMap() const + const StringifySerializer::ValueMap& StringifySerializer::GetValueMap() const { - return m_map; + return m_valueMap; } SerializerMode StringifySerializer::GetSerializerMode() const @@ -137,22 +137,22 @@ namespace AzNetworking template bool StringifySerializer::ProcessData(const char* name, const T& value) { - // Only add delimeters after we have processed at least one element + const AZStd::string keyString = m_prefix + name; + if (!m_string.empty()) { + // Only add delimeters after we have processed at least one element m_string += m_delimeter; } if (m_outputFieldNames) { - m_string += m_prefix; - m_string += name; - m_string += m_separator; + m_string += keyString; } - AZ::CVarFixedString string = AZ::ConsoleTypeHelpers::ValueToString(value); - m_string += string.c_str(); - m_map[m_prefix + name] = string.c_str(); + AZ::CVarFixedString valueString = AZ::ConsoleTypeHelpers::ValueToString(value); + m_valueMap[keyString] = valueString.c_str(); + return true; } } diff --git a/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.h b/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.h index d93f08822b..379b5198c7 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.h +++ b/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.h @@ -20,17 +20,15 @@ namespace AzNetworking { public: - using StringMap = AZStd::map; + using ValueMap = AZStd::map; StringifySerializer(char delimeter = ' ', bool outputFieldNames = true, const AZStd::string& seperator = "="); - // GetString - // After serializing objects, get the serialized values as a single string + //! After serializing objects, get the serialized values as a single string. const AZStd::string& GetString() const; - // GetValueMap - // After serializing objects, get the serialized values as key value pairs - const StringMap& GetValueMap() const; + //! After serializing objects, get the serialized values as a map of key/value pairs. + const ValueMap& GetValueMap() const; // ISerializer interfaces SerializerMode GetSerializerMode() const override; @@ -67,7 +65,7 @@ namespace AzNetworking char m_delimeter; bool m_outputFieldNames = true; - StringMap m_map; + ValueMap m_valueMap; AZStd::string m_string; AZStd::string m_prefix; AZStd::string m_separator; diff --git a/Gems/Multiplayer/Code/CMakeLists.txt b/Gems/Multiplayer/Code/CMakeLists.txt index 96527fbfc4..e8b38c8799 100644 --- a/Gems/Multiplayer/Code/CMakeLists.txt +++ b/Gems/Multiplayer/Code/CMakeLists.txt @@ -79,7 +79,7 @@ ly_add_target( # The "Multiplayer" target is used by clients and servers, Debug is used only on clients. ly_create_alias(NAME Multiplayer.Clients NAMESPACE Gem TARGETS Gem::Multiplayer Gem::Multiplayer.Debug) -ly_create_alias(NAME Multiplayer.Servers NAMESPACE Gem TARGETS Gem::Multiplayer) +ly_create_alias(NAME Multiplayer.Servers NAMESPACE Gem TARGETS Gem::Multiplayer Gem::Multiplayer.Debug) if (PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/Components/LocalPredictionPlayerInputComponent.h b/Gems/Multiplayer/Code/Include/Multiplayer/Components/LocalPredictionPlayerInputComponent.h index fbb7131f76..4e5d7f2d49 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/Components/LocalPredictionPlayerInputComponent.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Components/LocalPredictionPlayerInputComponent.h @@ -10,6 +10,7 @@ #include #include +#include namespace Multiplayer { @@ -41,8 +42,7 @@ namespace Multiplayer ( AzNetworking::IConnection* invokingConnection, const Multiplayer::NetworkInputArray& inputArray, - const AZ::HashValue32& stateHash, - const AzNetworking::PacketEncodingBuffer& clientState + const AZ::HashValue32& stateHash ) override; void HandleSendMigrateClientInput @@ -58,11 +58,6 @@ namespace Multiplayer const AzNetworking::PacketEncodingBuffer& correction ) override; - //! Return true if we're currently replaying inputs after a correction. - //! If this value returns true, effects, audio, and other cosmetic triggers should be suppressed - //! @return true if we're within correction scope and replaying inputs - bool IsReplayingInput() const; - //! Return true if we're currently migrating from one host to another. //! @return boolean true if we're currently migrating from one host to another bool IsMigrating() const; @@ -79,6 +74,9 @@ namespace Multiplayer void UpdateAutonomous(AZ::TimeMs deltaTimeMs); void UpdateBankedTime(AZ::TimeMs deltaTimeMs); + using StateHistoryItem = AZStd::unique_ptr; + AZStd::map m_predictiveStateHistory; + // Implicitly sorted player input history, back() is the input that corresponds to the latest client input Id NetworkInputHistory m_inputHistory; @@ -104,7 +102,6 @@ namespace Multiplayer ClientInputId m_lastMigratedInputId = ClientInputId{ 0 }; // Used to resend inputs that were queued during a migration event HostFrameId m_serverMigrateFrameId = InvalidHostFrameId; - bool m_replayingInput = false; // True if we're replaying inputs under a correction event (use this to suppress effects or audio) bool m_allowMigrateClientInput = false; // True if this component was migrated, we will allow the client to send us migrated inputs (one time only) }; } diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetBindComponent.h b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetBindComponent.h index e0574e23a3..c050495f1f 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetBindComponent.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetBindComponent.h @@ -87,9 +87,19 @@ namespace Multiplayer AzNetworking::ConnectionId GetOwningConnectionId() const; void SetAllowAutonomy(bool value); MultiplayerComponentInputVector AllocateComponentInputs(); + + //! Return true if we're currently processing inputs. + //! @return true if we're within ProcessInput scope and writing to predictive state bool IsProcessingInput() const; + + //! Return true if we're currently replaying inputs after a correction. + //! If this value returns true, effects, audio, and other cosmetic triggers should be suppressed + //! @return true if we're within correction scope and replaying inputs + bool IsReprocessingInput() const; + void CreateInput(NetworkInput& networkInput, float deltaTime); void ProcessInput(NetworkInput& networkInput, float deltaTime); + void ReprocessInput(NetworkInput& networkInput, float deltaTime); bool HandleRpcMessage(AzNetworking::IConnection* invokingConnection, NetEntityRole remoteRole, NetworkEntityRpcMessage& message); bool HandlePropertyChangeMessage(AzNetworking::ISerializer& serializer, bool notifyChanges = true); @@ -177,10 +187,11 @@ namespace Multiplayer AzNetworking::ConnectionId m_owningConnectionId = AzNetworking::InvalidConnectionId; - bool m_isProcessingInput = false; - bool m_isMigrationDataValid = false; - bool m_needsToBeStopped = false; - bool m_allowAutonomy = false; // Set to true for the hosts controlled entity + bool m_isProcessingInput = false; // Set to true when we are processing input + bool m_isReprocessingInput = false; // Set to true when we are reprocessing input (during a correction) + bool m_isMigrationDataValid = false; + bool m_needsToBeStopped = false; + bool m_allowAutonomy = false; // Set to true for the hosts controlled entity friend class NetworkEntityManager; friend class EntityReplicationManager; diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/INetworkTime.h b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/INetworkTime.h index 35ea317f62..441ad9876a 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/INetworkTime.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/INetworkTime.h @@ -54,6 +54,11 @@ namespace Multiplayer //! @return the HostFrameId taking into account the provided rewinding connectionId virtual HostFrameId GetHostFrameIdForRewindingConnection(AzNetworking::ConnectionId rewindConnectionId) const = 0; + //! Forcibly sets the current network time to the provided frameId and game time in milliseconds. + //! @param frameId the new HostFrameId to use + //! @param timeMs the new HostTimeMs to use + virtual void ForceSetTime(HostFrameId frameId, AZ::TimeMs timeMs) = 0; + //! Alters the current HostFrameId and binds that alteration to the provided ConnectionId. //! @param frameId the new HostFrameId to use //! @param timeMs the new HostTimeMs to use diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.inl b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.inl index b3a14e698b..496e87a7a2 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.inl +++ b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkTime/RewindableObject.inl @@ -72,7 +72,7 @@ namespace Multiplayer const HostFrameId frameTime = GetCurrentTimeForProperty(); if (frameTime < m_headTime) { - AZ_Assert(false, "Trying to mutate a rewindable in the past"); + AZ_Assert(false, "Trying to mutate a rewindable value in the past"); } else if (m_headTime < frameTime) { diff --git a/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml b/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml index 0c799a7b3f..1a7496a77d 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml +++ b/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml @@ -22,7 +22,6 @@ - diff --git a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp index df0d84c427..58e8890672 100644 --- a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp @@ -21,9 +21,11 @@ namespace Multiplayer AZ_CVAR(AZ::TimeMs, cl_MaxRewindHistoryMs, AZ::TimeMs{ 2000 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Maximum number of milliseconds to keep for server correction rewind and replay"); #ifndef AZ_RELEASE_BUILD AZ_CVAR(float, cl_DebugHackTimeMultiplier, 1.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "Scalar value used to simulate clock hacking cheats for validating bank time system and anticheat"); - AZ_CVAR(bool, cl_EnableDesyncDebugging, false, nullptr, AZ::ConsoleFunctorFlags::Null, "If enabled, debug logs will contain verbose information on detected state desyncs"); + AZ_CVAR(bool, cl_EnableDesyncDebugging, true, nullptr, AZ::ConsoleFunctorFlags::Null, "If enabled, debug logs will contain verbose information on detected state desyncs"); + AZ_CVAR(uint32_t, cl_PredictiveStateHistorySize, 120, nullptr, AZ::ConsoleFunctorFlags::Null, "Controls how many inputs of predictive state should be retained for debugging desyncs"); #endif + AZ_CVAR(bool, sv_ForceCorrections, false, nullptr, AZ::ConsoleFunctorFlags::Null, "If enabled, the server will force a correction for every input received for debugging"); AZ_CVAR(bool, sv_EnableCorrections, true, nullptr, AZ::ConsoleFunctorFlags::Null, "Enables server corrections on autonomous proxy desyncs"); AZ_CVAR(double, sv_MaxBankTimeWindowSec, 0.2, nullptr, AZ::ConsoleFunctorFlags::Null, "Maximum bank time we allow before we start rejecting autonomous proxy move inputs due to anticheat kicking in"); AZ_CVAR(double, sv_BankTimeDecay, 0.025, nullptr, AZ::ConsoleFunctorFlags::Null, "Amount to decay bank time by, in case of more permanent shifts in client latency"); @@ -45,6 +47,40 @@ namespace Multiplayer return serializer.GetString(); } + void PrintCorrectionDifferences(const AzNetworking::StringifySerializer& client, const AzNetworking::StringifySerializer& server) + { + const auto& clientMap = client.GetValueMap(); + const auto& serverMap = server.GetValueMap(); + + AzNetworking::StringifySerializer::ValueMap differences = clientMap; + for (auto iter = server.GetValueMap().begin(); iter != server.GetValueMap().end(); ++iter) + { + auto serverValueIter = clientMap.find(iter->first); + if (iter->second == differences[iter->first]) + { + differences.erase(iter->first); + } + } + + if (differences.empty()) + { + AZLOG_ERROR("The hash mismatched, but no differences were found.") + } + + for (auto iter = differences.begin(); iter != differences.end(); ++iter) + { + auto clientValueIter = clientMap.find(iter->first); + auto serverValueIter = serverMap.find(iter->first); + if (clientValueIter == clientMap.end() || serverValueIter == serverMap.end()) + { + AZLOG_ERROR(" %s (Not found in server and/or client value map!)", iter->first.c_str()); + continue; + } + + AZLOG_ERROR(" %s Server=%s Client=%s", iter->first.c_str(), serverValueIter->second.c_str(), clientValueIter->second.c_str()); + } + } + void LocalPredictionPlayerInputComponent::LocalPredictionPlayerInputComponent::Reflect(AZ::ReflectContext* context) { AZ::SerializeContext* serializeContext = azrtti_cast(context); @@ -106,8 +142,7 @@ namespace Multiplayer ( AzNetworking::IConnection* invokingConnection, const Multiplayer::NetworkInputArray& inputArray, - const AZ::HashValue32& stateHash, - [[maybe_unused]] const AzNetworking::PacketEncodingBuffer& clientState + const AZ::HashValue32& stateHash ) { if (invokingConnection == nullptr) @@ -176,7 +211,7 @@ namespace Multiplayer } } - if (sv_EnableCorrections && (currentTimeMs - m_lastCorrectionSentTimeMs > sv_MinCorrectionTimeMs)) + if (sv_ForceCorrections || (sv_EnableCorrections && (currentTimeMs - m_lastCorrectionSentTimeMs > sv_MinCorrectionTimeMs))) { m_lastCorrectionSentTimeMs = currentTimeMs; @@ -210,69 +245,6 @@ namespace Multiplayer // Send correction SendClientInputCorrection(GetLastInputId(), correction); - -#ifndef AZ_RELEASE_BUILD - AZStd::string clientStateString; - AZStd::string serverStateString; - if (cl_EnableDesyncDebugging) - { - // In debug, show which states caused the correction - // Write in client state - AzNetworking::NetworkOutputSerializer clientStateSerializer(clientState.GetBuffer(), clientState.GetSize()); - GetNetBindComponent()->SerializeEntityCorrection(clientStateSerializer); - - // Read out state values - AzNetworking::StringifySerializer clientValues; - GetNetBindComponent()->SerializeEntityCorrection(clientValues); - - // Restore server state - AzNetworking::NetworkOutputSerializer serverStateSerializer(correction.GetBuffer(), correction.GetSize()); - GetNetBindComponent()->SerializeEntityCorrection(serverStateSerializer); - - // Read out state values - AzNetworking::StringifySerializer serverValues; - GetNetBindComponent()->SerializeEntityCorrection(serverValues); - - AZStd::map> mapComparison; - - // put the server value in the first part of the pair - for (const auto& pair : serverValues.GetValueMap()) - { - mapComparison[pair.first].first = pair.second; - } - - // put the client value in the second part of the pair - for (const auto& pair : clientValues.GetValueMap()) - { - mapComparison[pair.first].second = pair.second; - } - - bool firstIt = true; - for (const auto& mapPair : mapComparison) - { - if (mapPair.second.first != mapPair.second.second) - { - if (!firstIt) - { - clientStateString += ","; - serverStateString += ","; - } - firstIt = false; - - AZStd::string clientValue = mapPair.second.second.empty() ? "" : mapPair.second.second; - AZStd::string serverValue = mapPair.second.first.empty() ? "" : mapPair.second.first; - clientStateString += mapPair.first + "=" + clientValue; - serverStateString += mapPair.first + "=" + serverValue; - } - } - } - else - { - clientStateString = "available in debug only"; - serverStateString = "available in debug only"; - } - AZLOG_ERROR("** Autonomous proxy desync detected! ** clientState=[%s], serverState=[%s]", clientStateString.c_str(), serverStateString.c_str()); -#endif } } } @@ -331,7 +303,7 @@ namespace Multiplayer void LocalPredictionPlayerInputComponentController::HandleSendClientInputCorrection ( - AzNetworking::IConnection* invokingConnection, + [[maybe_unused]] AzNetworking::IConnection* invokingConnection, const Multiplayer::ClientInputId& inputId, const AzNetworking::PacketEncodingBuffer& correction ) @@ -356,6 +328,25 @@ namespace Multiplayer GetNetBindComponent()->SerializeEntityCorrection(serializer); m_correctionEvent.Signal(); +#ifndef AZ_RELEASE_BUILD + if (cl_EnableDesyncDebugging) + { + AZLOG_INFO("** Autonomous Desync - Corrected clientInputId=%d ", aznumeric_cast(inputId)); + auto iter = m_predictiveStateHistory.find(inputId); + if (iter != m_predictiveStateHistory.end()) + { + // Read out state values + AzNetworking::StringifySerializer serverValues; + GetNetBindComponent()->SerializeEntityCorrection(serverValues); + PrintCorrectionDifferences(*iter->second, serverValues); + } + else + { + AZLOG_INFO("Received correction that is too old to diff, increase cl_PredictiveStateHistorySize"); + } + } +#endif + AZLOG ( NET_Prediction, @@ -370,29 +361,13 @@ namespace Multiplayer // If this correction is for a move outside our input history window, just start replaying from the oldest move we have available const uint32_t startReplayIndex = (inputHistorySize > historicalDelta) ? (inputHistorySize - historicalDelta) : 0; - // Flag that we are replaying inputs - struct ScopedReplayingInput - { - ScopedReplayingInput(LocalPredictionPlayerInputComponentController* instance) - : m_instance(instance) - { - m_instance->m_replayingInput = true; - } - ~ScopedReplayingInput() - { - m_instance->m_replayingInput = false; - } - LocalPredictionPlayerInputComponentController* m_instance; - }; - ScopedReplayingInput markReplayingInput(this); - const float clientInputRateSec = static_cast(static_cast(cl_InputRateMs)) / 1000.0; for (uint32_t replayIndex = startReplayIndex; replayIndex < inputHistorySize; ++replayIndex) { // Reprocess the input for this frame NetworkInput& input = m_inputHistory[replayIndex]; ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), invokingConnection->GetConnectionId()); - GetNetBindComponent()->ProcessInput(input, clientInputRateSec); + GetNetBindComponent()->ReprocessInput(input, clientInputRateSec); AZLOG ( @@ -405,11 +380,6 @@ namespace Multiplayer } } - bool LocalPredictionPlayerInputComponentController::IsReplayingInput() const - { - return m_replayingInput; - } - bool LocalPredictionPlayerInputComponentController::IsMigrating() const { return m_lastMigratedInputId != ClientInputId{ 0 }; @@ -519,17 +489,6 @@ namespace Multiplayer AzNetworking::HashSerializer hashSerializer; GetNetBindComponent()->SerializeEntityCorrection(hashSerializer); - // In debug, send the entire client output state to the server to make it easier to debug desync issues - AzNetworking::PacketEncodingBuffer processInputResult; -#ifndef AZ_RELEASE_BUILD - if (cl_EnableDesyncDebugging) - { - AzNetworking::NetworkInputSerializer processInputResultSerializer(processInputResult.GetBuffer(), processInputResult.GetCapacity()); - GetNetBindComponent()->SerializeEntityCorrection(processInputResultSerializer); - processInputResult.Resize(processInputResultSerializer.GetSize()); - } -#endif - // Save this input and discard move history outside our client rewind window m_inputHistory.PushBack(input); while (m_inputHistory.Size() > maxClientInputs) @@ -548,10 +507,23 @@ namespace Multiplayer inputArray[i] = m_inputHistory[historyIndex]; } +#ifndef AZ_RELEASE_BUILD + if (cl_EnableDesyncDebugging) + { + StateHistoryItem inputHistory = AZStd::make_unique(); + while (m_predictiveStateHistory.size() > cl_PredictiveStateHistorySize) + { + m_predictiveStateHistory.erase(m_predictiveStateHistory.begin()); + } + GetNetBindComponent()->SerializeEntityCorrection(*inputHistory); + m_predictiveStateHistory.emplace(m_clientInputId, AZStd::move(inputHistory)); + } +#endif + // Send the input to server (only when we are not migrating) if (!IsMigrating()) { - SendClientInput(inputArray, hashSerializer.GetHash(), processInputResult); + SendClientInput(inputArray, hashSerializer.GetHash()); } } } diff --git a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp index e8da34fc7f..cbbbadeffa 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp @@ -267,6 +267,11 @@ namespace Multiplayer return m_isProcessingInput; } + bool NetBindComponent::IsReprocessingInput() const + { + return m_isReprocessingInput; + } + void NetBindComponent::CreateInput(NetworkInput& networkInput, float deltaTime) { // Only autonomous or authority runs this logic @@ -279,12 +284,21 @@ namespace Multiplayer void NetBindComponent::ProcessInput(NetworkInput& networkInput, float deltaTime) { + m_isProcessingInput = true; // Only autonomous and authority runs this logic AZ_Assert((NetworkRoleHasController(m_netEntityRole)), "Incorrect network role for input processing"); for (MultiplayerComponent* multiplayerComponent : m_multiplayerInputComponentVector) { multiplayerComponent->GetController()->ProcessInput(networkInput, deltaTime); } + m_isProcessingInput = false; + } + + void NetBindComponent::ReprocessInput(NetworkInput& networkInput, float deltaTime) + { + m_isReprocessingInput = true; + ProcessInput(networkInput, deltaTime); + m_isReprocessingInput = false; } bool NetBindComponent::HandleRpcMessage(AzNetworking::IConnection* invokingConnection, NetEntityRole remoteRole, NetworkEntityRpcMessage& message) @@ -649,6 +663,7 @@ namespace Multiplayer MultiplayerComponent* multiplayerComponent = azrtti_cast(component); if (multiplayerComponent != nullptr) { + multiplayerComponent->SetOwningConnectionId(m_owningConnectionId); m_multiplayerInputComponentVector.push_back(multiplayerComponent); } } diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index 21c7ce80d6..16df4a629a 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -554,7 +554,7 @@ namespace Multiplayer m_tickFactor = 0.0f; m_lastReplicatedHostTimeMs = packet.GetHostTimeMs(); m_lastReplicatedHostFrameId = packet.GetHostFrameId(); - m_networkTime.AlterTime(m_lastReplicatedHostFrameId, m_lastReplicatedHostTimeMs, AzNetworking::InvalidConnectionId); + m_networkTime.ForceSetTime(m_lastReplicatedHostFrameId, m_lastReplicatedHostTimeMs); } for (AZStd::size_t i = 0; i < packet.GetEntityMessages().size(); ++i) @@ -856,7 +856,7 @@ namespace Multiplayer { m_tickFactor += deltaTime / serverRateSeconds; // Linear close to the origin, but asymptote at y = 1 - const float renderBlendFactor = AZStd::clamp(1.0f - (std::pow(cl_renderTickBlendBase, m_tickFactor)), 0.0f, 1.0f); + const float renderBlendFactor = AZStd::clamp(1.0f - (std::pow(cl_renderTickBlendBase, m_tickFactor)), 0.0f, m_tickFactor); AZLOG ( NET_Blending, diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp index b9e9a9a87e..78e90cc7fb 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp @@ -524,6 +524,7 @@ namespace Multiplayer bool EntityReplicationManager::HandlePropertyChangeMessage ( + AzNetworking::IConnection* invokingConnection, EntityReplicator* entityReplicator, AzNetworking::PacketId packetId, NetEntityId netEntityId, @@ -558,6 +559,12 @@ namespace Multiplayer NetBindComponent* netBindComponent = replicatorEntity.GetNetBindComponent(); AZ_Assert(netBindComponent != nullptr, "No NetBindComponent"); + if (createEntity) + { + // Always set our invoking connectionId for any newly created entities, since this connection now 'owns' them from a rewind perspective + netBindComponent->SetOwningConnectionId(invokingConnection->GetConnectionId()); + } + const bool changeNetworkRole = (netBindComponent->GetNetEntityRole() != localNetworkRole); if (changeNetworkRole) { @@ -744,7 +751,7 @@ namespace Multiplayer bool EntityReplicationManager::HandleEntityUpdateMessage ( - [[maybe_unused]] AzNetworking::IConnection* invokingConnection, + AzNetworking::IConnection* invokingConnection, const AzNetworking::IPacketHeader& packetHeader, const NetworkEntityUpdateMessage& updateMessage ) @@ -794,7 +801,7 @@ namespace Multiplayer } // This may implicitly create a replicator for us - bool handled = HandlePropertyChangeMessage(entityReplicator, packetHeader.GetPacketId(), updateMessage.GetEntityId(), updateMessage.GetNetworkRole(), outputSerializer, prefabEntityId); + bool handled = HandlePropertyChangeMessage(invokingConnection, entityReplicator, packetHeader.GetPacketId(), updateMessage.GetEntityId(), updateMessage.GetNetworkRole(), outputSerializer, prefabEntityId); AZ_Assert(handled, "Failed to handle NetworkEntityUpdateMessage message"); return handled; @@ -1121,7 +1128,7 @@ namespace Multiplayer } } - bool EntityReplicationManager::HandleEntityMigration([[maybe_unused]] AzNetworking::IConnection* invokingConnection, EntityMigrationMessage& message) + bool EntityReplicationManager::HandleEntityMigration(AzNetworking::IConnection* invokingConnection, EntityMigrationMessage& message) { EntityReplicator* replicator = GetEntityReplicator(message.m_entityId); { @@ -1130,6 +1137,7 @@ namespace Multiplayer AzNetworking::TrackChangedSerializer outputSerializer(message.m_propertyUpdateData.GetBuffer(), message.m_propertyUpdateData.GetSize()); if (!HandlePropertyChangeMessage ( + invokingConnection, replicator, AzNetworking::InvalidPacketId, message.m_entityId, diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.h b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.h index 9f5e743bbc..731a1a7556 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.h +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.h @@ -136,6 +136,7 @@ namespace Multiplayer bool HandlePropertyChangeMessage ( + AzNetworking::IConnection* invokingConnection, EntityReplicator* entityReplicator, AzNetworking::PacketId packetId, NetEntityId netEntityId, diff --git a/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.cpp b/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.cpp index 645ce1fc00..5ae698e622 100644 --- a/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.cpp @@ -65,6 +65,15 @@ namespace Multiplayer return (IsTimeRewound() && (rewindConnectionId == m_rewindingConnectionId)) ? m_unalteredFrameId : m_hostFrameId; } + void NetworkTime::ForceSetTime(HostFrameId frameId, AZ::TimeMs timeMs) + { + AZ_Assert(!IsTimeRewound(), "Forcibly setting network time is unsupported under a rewound time scope"); + m_unalteredFrameId = frameId; + m_hostFrameId = frameId; + m_hostTimeMs = timeMs; + m_rewindingConnectionId = AzNetworking::InvalidConnectionId; + } + void NetworkTime::AlterTime(HostFrameId frameId, AZ::TimeMs timeMs, AzNetworking::ConnectionId rewindConnectionId) { m_hostFrameId = frameId; diff --git a/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.h b/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.h index 4d568f40d9..4b94d3b6f2 100644 --- a/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.h +++ b/Gems/Multiplayer/Code/Source/NetworkTime/NetworkTime.h @@ -32,6 +32,7 @@ namespace Multiplayer AZ::TimeMs GetHostTimeMs() const override; AzNetworking::ConnectionId GetRewindingConnectionId() const override; HostFrameId GetHostFrameIdForRewindingConnection(AzNetworking::ConnectionId rewindConnectionId) const override; + void ForceSetTime(HostFrameId frameId, AZ::TimeMs timeMs) override; void AlterTime(HostFrameId frameId, AZ::TimeMs timeMs, AzNetworking::ConnectionId rewindConnectionId) override; void SyncEntitiesToRewindState(const AZ::Aabb& rewindVolume) override; void ClearRewoundEntities() override; From 699e8edb360da3916a8fa925735bb342627a564b Mon Sep 17 00:00:00 2001 From: kberg-amzn Date: Wed, 28 Jul 2021 12:31:19 -0700 Subject: [PATCH 02/70] Corrects math computing blend factors to interpolate state between received network updates Signed-off-by: kberg-amzn --- .../Source/MultiplayerSystemComponent.cpp | 37 +++++++++++++------ .../Code/Source/MultiplayerSystemComponent.h | 2 +- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index 9a46bb10de..21c7ce80d6 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -69,19 +69,24 @@ namespace Multiplayer { using namespace AzNetworking; - AZ_CVAR(uint16_t, cl_clientport, 0, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The port to bind to for game traffic when connecting to a remote host, a value of 0 will select any available port"); - AZ_CVAR(AZ::CVarFixedString, cl_serveraddr, AZ::CVarFixedString(LocalHost), nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The address of the remote server or host to connect to"); - AZ_CVAR(AZ::CVarFixedString, cl_serverpassword, "", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Optional server password"); + AZ_CVAR(uint16_t, cl_clientport, 0, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, + "The port to bind to for game traffic when connecting to a remote host, a value of 0 will select any available port"); + AZ_CVAR(AZ::CVarFixedString, cl_serveraddr, AZ::CVarFixedString(LocalHost), nullptr, AZ::ConsoleFunctorFlags::DontReplicate, + "The address of the remote server or host to connect to"); AZ_CVAR(uint16_t, cl_serverport, DefaultServerPort, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The port of the remote host to connect to for game traffic"); AZ_CVAR(uint16_t, sv_port, DefaultServerPort, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The port that this multiplayer gem will bind to for game traffic"); AZ_CVAR(AZ::CVarFixedString, sv_map, "nolevel", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The map the server should load"); - AZ_CVAR(AZ::CVarFixedString, sv_gamerules, "norules", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "GameRules server works with"); AZ_CVAR(ProtocolType, sv_protocol, ProtocolType::Udp, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "This flag controls whether we use TCP or UDP for game networking"); AZ_CVAR(bool, sv_isDedicated, true, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Whether the host command creates an independent or client hosted server"); AZ_CVAR(bool, sv_isTransient, true, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Whether a dedicated server shuts down if all existing connections disconnect."); - AZ_CVAR(AZ::TimeMs, cl_defaultNetworkEntityActivationTimeSliceMs, AZ::TimeMs{ 0 }, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Max Ms to use to activate entities coming from the network, 0 means instantiate everything"); + AZ_CVAR(AZ::TimeMs, cl_defaultNetworkEntityActivationTimeSliceMs, AZ::TimeMs{ 0 }, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, + "Max Ms to use to activate entities coming from the network, 0 means instantiate everything"); AZ_CVAR(AZ::TimeMs, sv_serverSendRateMs, AZ::TimeMs{ 50 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Minimum number of milliseconds between each network update"); - AZ_CVAR(AZ::CVarFixedString, sv_defaultPlayerSpawnAsset, "prefabs/player.network.spawnable", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The default spawnable to use when a new player connects"); + AZ_CVAR(AZ::CVarFixedString, sv_defaultPlayerSpawnAsset, "prefabs/player.network.spawnable", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, + "The default spawnable to use when a new player connects"); + AZ_CVAR(float, cl_renderTickBlendBase, 0.15f, nullptr, AZ::ConsoleFunctorFlags::Null, + "The base used for blending between network updates, 0.1 will be quite linear, 0.2 or 0.3 will " + "slow down quicker and may be better suited to connections with highly variable latency"); void MultiplayerSystemComponent::Reflect(AZ::ReflectContext* context) { @@ -546,7 +551,7 @@ namespace Multiplayer if ((GetAgentType() == MultiplayerAgentType::Client) && (packet.GetHostFrameId() > m_lastReplicatedHostFrameId)) { // Update client to latest server time - m_renderBlendFactor = 0.0f; + m_tickFactor = 0.0f; m_lastReplicatedHostTimeMs = packet.GetHostTimeMs(); m_lastReplicatedHostFrameId = packet.GetHostFrameId(); m_networkTime.AlterTime(m_lastReplicatedHostFrameId, m_lastReplicatedHostTimeMs, AzNetworking::InvalidConnectionId); @@ -849,10 +854,18 @@ namespace Multiplayer void MultiplayerSystemComponent::TickVisibleNetworkEntities(float deltaTime, float serverRateSeconds) { + m_tickFactor += deltaTime / serverRateSeconds; // Linear close to the origin, but asymptote at y = 1 - const float targetAdjustBlend = AZStd::clamp(deltaTime / serverRateSeconds, 0.0f, 1.0f); - m_renderBlendFactor = 1.0f - (std::pow(0.2f, m_renderBlendFactor + targetAdjustBlend)); - AZLOG(NET_Blending, "Computed blend factor of %0.2f using a frametime of %0.2f and a serverTickRate of %0.2f", m_renderBlendFactor, deltaTime, serverRateSeconds); + const float renderBlendFactor = AZStd::clamp(1.0f - (std::pow(cl_renderTickBlendBase, m_tickFactor)), 0.0f, 1.0f); + AZLOG + ( + NET_Blending, + "Computed blend factor of %0.3f using a tick factor of %0.3f, a frametime of %0.3f and a serverTickRate of %0.3f", + renderBlendFactor, + m_tickFactor, + deltaTime, + serverRateSeconds + ); if (Camera::ActiveCameraRequestBus::HasHandlers()) { @@ -895,7 +908,7 @@ namespace Multiplayer for (NetBindComponent* netBindComponent : gatheredEntities) { - netBindComponent->NotifyPreRender(deltaTime, m_renderBlendFactor); + netBindComponent->NotifyPreRender(deltaTime, renderBlendFactor); } } else @@ -907,7 +920,7 @@ namespace Multiplayer NetBindComponent* netBindComponent = entity->FindComponent(); if (netBindComponent != nullptr) { - netBindComponent->NotifyPreRender(deltaTime, m_renderBlendFactor); + netBindComponent->NotifyPreRender(deltaTime, renderBlendFactor); } } } diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h index 37e8138a71..ab37958962 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h @@ -155,7 +155,7 @@ namespace Multiplayer HostFrameId m_lastReplicatedHostFrameId = HostFrameId(0); double m_serverSendAccumulator = 0.0; - float m_renderBlendFactor = 0.0f; + float m_tickFactor = 0.0f; #if !defined(AZ_RELEASE_BUILD) MultiplayerEditorConnection m_editorConnectionListener; From 2f5927f1ac43c3f082cd3b3e69084d9d2c14554e Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Fri, 6 Aug 2021 17:45:54 -0700 Subject: [PATCH 03/70] [redcode/crythread-2nd-pass] remove dependency on cry threads in the remote console runtime Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- .../RemoteConsole/Core/RemoteConsoleCore.cpp | 88 +++++++++++-------- .../RemoteConsole/Core/RemoteConsoleCore.h | 42 ++++++--- 2 files changed, 84 insertions(+), 46 deletions(-) diff --git a/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.cpp b/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.cpp index d4ef5b3ba8..94ae4cbfbf 100644 --- a/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.cpp +++ b/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.cpp @@ -93,40 +93,63 @@ bool RCON_IsRemoteAllowedToConnect(const AZ::AzSock::AzSocketAddress& connectee) ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// +void SRemoteThreadedObject::Start(const char* name) +{ + AZStd::thread_desc desc; + desc.m_name = name; + auto function = AZStd::bind(&SRemoteThreadedObject::ThreadFunction, this); + m_thread = AZStd::thread(function, &desc); +} + +void SRemoteThreadedObject::WaitForThread() +{ + if (m_thread.joinable()) + { + m_thread.join(); + } +} + +void SRemoteThreadedObject::ThreadFunction() +{ + Run(); + Terminate(); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// void SRemoteServer::StartServer() { StopServer(); m_bAcceptClients = true; - Start(0, kServerThreadName); + Start(kServerThreadName); } ///////////////////////////////////////////////////////////////////////////////////////////// void SRemoteServer::StopServer() { - Stop(); m_bAcceptClients = false; AZ::AzSock::CloseSocket(m_socket); m_socket = SOCKET_ERROR; - m_lock.Lock(); - for (TClients::iterator it = m_clients.begin(); it != m_clients.end(); ++it) { - it->pClient->StopClient(); + AZStd::lock_guard lock(m_mutex); + for (TClients::iterator it = m_clients.begin(); it != m_clients.end(); ++it) + { + it->pClient->StopClient(); + } } - m_lock.Unlock(); - m_stopEvent.Wait(); - m_stopEvent.Set(); -} + AZStd::unique_lock lock(m_mutex); + m_stopCondition.wait(lock, [this] { return m_clients.empty(); });} ///////////////////////////////////////////////////////////////////////////////////////////// void SRemoteServer::ClientDone(SRemoteClient* pClient) { - m_lock.Lock(); + AZStd::lock_guard lock(m_mutex); for (TClients::iterator it = m_clients.begin(); it != m_clients.end(); ++it) { if (it->pClient == pClient) { - it->pClient->Stop(); delete it->pClient; delete it->pEvents; m_clients.erase(it); @@ -136,9 +159,8 @@ void SRemoteServer::ClientDone(SRemoteClient* pClient) if (m_clients.empty()) { - m_stopEvent.Set(); + m_stopCondition.notify_all(); } - m_lock.Unlock(); } ///////////////////////////////////////////////////////////////////////////////////////////// @@ -149,7 +171,6 @@ void SRemoteServer::Terminate() ///////////////////////////////////////////////////////////////////////////////////////////// void SRemoteServer::Run() { - SetName(kServerThreadName); AZ_TRAIT_REMOTECONSOLE_SET_THREAD_AFFINITY AZSOCKET sClient; @@ -232,12 +253,10 @@ void SRemoteServer::Run() continue; } - m_lock.Lock(); - m_stopEvent.Reset(); + AZStd::lock_guard lock(m_mutex); SRemoteClient* pClient = new SRemoteClient(this); m_clients.push_back(SRemoteClientInfo(pClient)); pClient->StartClient(sClient); - m_lock.Unlock(); } AZ::AzSock::CloseSocket(m_socket); CryLog("Remote console terminating.\n"); @@ -247,43 +266,42 @@ void SRemoteServer::Run() ///////////////////////////////////////////////////////////////////////////////////////////// void SRemoteServer::AddEvent(IRemoteEvent* pEvent) { - m_lock.Lock(); + AZStd::lock_guard lock(m_mutex); for (TClients::iterator it = m_clients.begin(); it != m_clients.end(); ++it) { it->pEvents->push_back(pEvent->Clone()); } - m_lock.Unlock(); delete pEvent; } ///////////////////////////////////////////////////////////////////////////////////////////// void SRemoteServer::GetEvents(TEventBuffer& buffer) { - m_lock.Lock(); + AZStd::lock_guard lock(m_mutex); buffer = m_eventBuffer; m_eventBuffer.clear(); - m_lock.Unlock(); } ///////////////////////////////////////////////////////////////////////////////////////////// bool SRemoteServer::WriteBuffer(SRemoteClient* pClient, char* buffer, int& size) { - m_lock.Lock(); IRemoteEvent* pEvent = nullptr; - for (TClients::iterator it = m_clients.begin(); it != m_clients.end(); ++it) { - if (it->pClient == pClient) + AZStd::lock_guard lock(m_mutex); + for (TClients::iterator it = m_clients.begin(); it != m_clients.end(); ++it) { - TEventBuffer* pEvents = it->pEvents; - if (!pEvents->empty()) + if (it->pClient == pClient) { - pEvent = pEvents->front(); - pEvents->pop_front(); + TEventBuffer* pEvents = it->pEvents; + if (!pEvents->empty()) + { + pEvent = pEvents->front(); + pEvents->pop_front(); + } + break; } - break; } } - m_lock.Unlock(); const bool res = (pEvent != nullptr); if (pEvent) { @@ -297,7 +315,7 @@ bool SRemoteServer::WriteBuffer(SRemoteClient* pClient, char* buffer, int& size bool SRemoteServer::ReadBuffer(const char* buffer, int data) { bool result = true; - + // Sometimes multiple events can come in a single buffer, so make sure we look // at the entire thing. int bytesRemaining = data; @@ -306,15 +324,14 @@ bool SRemoteServer::ReadBuffer(const char* buffer, int data) { // Create the event from the current sub string in the buffer. IRemoteEvent* event = SRemoteEventFactory::GetInst()->CreateEventFromBuffer(curBuffer, bytesRemaining); - + result &= (event != nullptr); if (event) { if (event->GetType() != eCET_Noop) { - m_lock.Lock(); + AZStd::lock_guard lock(m_mutex); m_eventBuffer.push_back(event); - m_lock.Unlock(); } else { @@ -337,7 +354,7 @@ bool SRemoteServer::ReadBuffer(const char* buffer, int data) void SRemoteClient::StartClient(AZSOCKET socket) { m_socket = socket; - Start(0, kClientThreadName); + Start(kClientThreadName); } ///////////////////////////////////////////////////////////////////////////////////////////// @@ -356,7 +373,6 @@ void SRemoteClient::Terminate() ///////////////////////////////////////////////////////////////////////////////////////////// void SRemoteClient::Run() { - SetName(kClientThreadName); AZ_TRAIT_REMOTECONSOLE_SET_THREAD_AFFINITY char szBuff[kDefaultBufferSize]; diff --git a/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.h b/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.h index 45c3bf62d9..7e22be5735 100644 --- a/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.h +++ b/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.h @@ -11,9 +11,11 @@ #include #include #include +#include +#include +#include #include -#include extern const int defaultRemoteConsolePort; @@ -146,6 +148,30 @@ private: typedef AZStd::list TEventBuffer; + +///////////////////////////////////////////////////////////////////////////////////////////// +// SRemoteThreadedObject +// +// Simple runnable-like threaded object +// +///////////////////////////////////////////////////////////////////////////////////////////// +struct SRemoteThreadedObject +{ + virtual ~SRemoteThreadedObject() = default; + + void Start(const char* name); + + void WaitForThread(); + + virtual void Run() = 0; + virtual void Terminate() = 0; + +private: + void ThreadFunction(); + + AZStd::thread m_thread; +}; + ///////////////////////////////////////////////////////////////////////////////////////////// // SRemoteServer // @@ -154,10 +180,10 @@ typedef AZStd::list TEventBuffer; ///////////////////////////////////////////////////////////////////////////////////////////// struct SRemoteClient; struct SRemoteServer - : public CrySimpleThread<> + : public SRemoteThreadedObject { SRemoteServer() - : m_socket(AZ_SOCKET_INVALID) { m_stopEvent.Set(); } + : m_socket(AZ_SOCKET_INVALID) {} void StartServer(); void StopServer(); @@ -165,10 +191,8 @@ struct SRemoteServer void AddEvent(IRemoteEvent* pEvent); void GetEvents(TEventBuffer& buffer); - // CrySimpleThread void Terminate() override; void Run() override; - // ~CrySimpleThread private: bool WriteBuffer(SRemoteClient* pClient, char* buffer, int& size); @@ -189,9 +213,9 @@ private: typedef AZStd::vector TClients; TClients m_clients; AZSOCKET m_socket; - CryMutex m_lock; + AZStd::recursive_mutex m_mutex; TEventBuffer m_eventBuffer; - CryEvent m_stopEvent; + AZStd::condition_variable_any m_stopCondition; volatile bool m_bAcceptClients; friend struct SRemoteClient; }; @@ -204,7 +228,7 @@ private: // ///////////////////////////////////////////////////////////////////////////////////////////// struct SRemoteClient - : public CrySimpleThread<> + : public SRemoteThreadedObject { SRemoteClient(SRemoteServer* pServer) : m_pServer(pServer) @@ -213,10 +237,8 @@ struct SRemoteClient void StartClient(AZSOCKET socket); void StopClient(); - // CrySimpleThread void Terminate() override; void Run() override; - // ~CrySimpleThread private: bool RecvPackage(char* buffer, int& size); From 3e7d7d150e72015fb57b3c4f2ef15bf5b95a45aa Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Fri, 6 Aug 2021 18:22:28 -0700 Subject: [PATCH 04/70] [redcode/crythread-2nd-pass] removed CryThread_dummy.h Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Code/Legacy/CryCommon/CryThread.h | 1 - Code/Legacy/CryCommon/CryThread_dummy.h | 152 -------------------- Code/Legacy/CryCommon/crycommon_files.cmake | 1 - 3 files changed, 154 deletions(-) delete mode 100644 Code/Legacy/CryCommon/CryThread_dummy.h diff --git a/Code/Legacy/CryCommon/CryThread.h b/Code/Legacy/CryCommon/CryThread.h index 5929bed352..b7b6a3adfd 100644 --- a/Code/Legacy/CryCommon/CryThread.h +++ b/Code/Legacy/CryCommon/CryThread.h @@ -175,7 +175,6 @@ class CrySimpleThread; #undef AZ_RESTRICTED_SECTION_IMPLEMENTED #else // Put other platform specific includes here! -#include #endif #if !defined _CRYTHREAD_CONDLOCK_GLITCH diff --git a/Code/Legacy/CryCommon/CryThread_dummy.h b/Code/Legacy/CryCommon/CryThread_dummy.h deleted file mode 100644 index d97b6c5b55..0000000000 --- a/Code/Legacy/CryCommon/CryThread_dummy.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - - -#ifndef CRYINCLUDE_CRYCOMMON_CRYTHREAD_DUMMY_H -#define CRYINCLUDE_CRYCOMMON_CRYTHREAD_DUMMY_H -#pragma once - -#include - -////////////////////////////////////////////////////////////////////////// -CryEvent::CryEvent() {} -CryEvent::~CryEvent() {} -void CryEvent::Reset() {} -void CryEvent::Set() {} -void CryEvent::Wait() const {} -bool CryEvent::Wait(const uint32 timeoutMillis) const {} -typedef CryEvent CryEventTimed; - -////////////////////////////////////////////////////////////////////////// -class _DummyLock -{ -public: - _DummyLock(); - - void Lock(); - bool TryLock(); - void Unlock(); - -#if defined(AZ_DEBUG_BUILD) - bool IsLocked(); -#endif -}; - -template<> -class CryLock - : public _DummyLock -{ - CryLock(const CryLock&); - void operator = (const CryLock&); - -public: - CryLock(); -}; - -template<> -class CryLock - : public _DummyLock -{ - CryLock(const CryLock&); - void operator = (const CryLock&); - -public: - CryLock(); -}; - -template<> -class CryCondLock - : public CryLock -{ -}; - -template<> -class CryCondLock - : public CryLock -{ -}; - -template<> -class CryCond< CryLock > -{ - typedef CryLock LockT; - CryCond(const CryCond&); - void operator = (const CryCond&); - -public: - CryCond(); - - void Notify(); - void NotifySingle(); - void Wait(LockT&); - bool TimedWait(LockT &, uint32); -}; - -template<> -class CryCond< CryLock > -{ - typedef CryLock LockT; - CryCond(const CryCond&); - void operator = (const CryCond&); - -public: - CryCond(); - - void Notify(); - void NotifySingle(); - void Wait(LockT&); - bool TimedWait(LockT &, uint32); -}; - -class _DummyRWLock -{ -public: - _DummyRWLock() { } - - void RLock(); - bool TryRLock(); - void WLock(); - bool TryWLock(); - void Lock() { WLock(); } - bool TryLock() { return TryWLock(); } - void Unlock(); -}; - -template -class CrySimpleThread - : public CryRunnable -{ -public: - typedef void (* ThreadFunction)(void*); - - CrySimpleThread(); - virtual ~CrySimpleThread(); -#if !defined(NO_THREADINFO) - CryThreadInfo& GetInfo(); -#endif - const char* GetName(); - void SetName(const char*); - - virtual void Run(); - virtual void Cancel(); - virtual void Start(Runnable&, unsigned = 0, const char* = NULL); - virtual void Start(unsigned = 0, const char* = NULL); - void StartFunction(ThreadFunction, void* = NULL, unsigned = 0); - - void Exit(); - void Join(); - unsigned SetCpuMask(unsigned); - unsigned GetCpuMask(); - - void Stop(); - bool IsStarted() const; - bool IsRunning() const; -}; - -#endif // CRYINCLUDE_CRYCOMMON_CRYTHREAD_DUMMY_H - diff --git a/Code/Legacy/CryCommon/crycommon_files.cmake b/Code/Legacy/CryCommon/crycommon_files.cmake index 0392f11c89..b4dac2ec08 100644 --- a/Code/Legacy/CryCommon/crycommon_files.cmake +++ b/Code/Legacy/CryCommon/crycommon_files.cmake @@ -160,7 +160,6 @@ set(FILES CryAssert_Mac.h CryLibrary.cpp CryLibrary.h - CryThread_dummy.h CryThread_pthreads.h CryThread_windows.h CryThreadImpl_pthreads.h From 4beb66c9caee9e9f1c3bce290c3ccc851ebe75d4 Mon Sep 17 00:00:00 2001 From: antonmic <56370189+antonmic@users.noreply.github.com> Date: Sun, 8 Aug 2021 23:37:54 -0700 Subject: [PATCH 05/70] Making pass files declare dependency on shader files (part 01) Signed-off-by: antonmic <56370189+antonmic@users.noreply.github.com> --- .../Code/Source/Editor/ShaderAssetBuilder.cpp | 3 +- .../Editor/ShaderVariantAssetBuilder.cpp | 2 +- .../Source/RPI.Builders/Pass/PassBuilder.cpp | 197 ++++++++++++++---- .../Source/RPI.Builders/Pass/PassBuilder.h | 1 - 4 files changed, 159 insertions(+), 44 deletions(-) diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp index b1a3de2794..606502fb22 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp @@ -139,8 +139,7 @@ namespace AZ AssetBuilderSDK::JobDescriptor jobDescriptor; jobDescriptor.m_priority = 2; - // [GFX TODO][ATOM-2830] Set 'm_critical' back to 'false' once proper fix for Atom startup issues are in - jobDescriptor.m_critical = true; + jobDescriptor.m_critical = false; jobDescriptor.m_jobKey = ShaderAssetBuilderJobKey; jobDescriptor.SetPlatformIdentifier(platformInfo.m_identifier.c_str()); jobDescriptor.m_jobParameters.emplace(ShaderAssetBuildTimestampParam, AZStd::to_string(shaderAssetBuildTimestamp)); diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp index 1da4623774..ee02ae8452 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp @@ -321,7 +321,7 @@ namespace AZ AssetBuilderSDK::JobDescriptor jobDescriptor; jobDescriptor.m_priority = -5000; - jobDescriptor.m_critical = false; + jobDescriptor.m_critical = true; jobDescriptor.m_jobKey = ShaderVariantAssetBuilderJobKey; jobDescriptor.SetPlatformIdentifier(info.m_identifier.data()); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.cpp index 652130dea2..f582f3ba04 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.cpp @@ -37,7 +37,7 @@ namespace AZ { AssetBuilderSDK::AssetBuilderDesc builder; builder.m_name = PassBuilderJobKey; - builder.m_version = 12; // ATOM-15472 + builder.m_version = 13; // antonmic: making .pass files declare dependency on shaders they reference builder.m_busId = azrtti_typeid(); builder.m_createJobFunction = AZStd::bind(&PassBuilder::CreateJobs, this, AZStd::placeholders::_1, AZStd::placeholders::_2); builder.m_processJobFunction = AZStd::bind(&PassBuilder::ProcessJob, this, AZStd::placeholders::_1, AZStd::placeholders::_2); @@ -65,35 +65,66 @@ namespace AZ m_isShuttingDown = true; } - void PassBuilder::CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response) const + // --- Code related to dependency shader asset handling --- + + struct FindPassReferenceAssetParams { - if (m_isShuttingDown) + void* passAssetObject; + Uuid passAssetUuid; + SerializeContext* serializeContext; + AZStd::string_view passAssetSourceFile; // File path of the pass asset + AZStd::string_view dependencySourceFile; // File pass of the asset the pass asset depends on + const char* jobKey; // Job key for adding job dependency + }; + + //! Adds all relevant dependencies for a referenced source file, considering that the path might be relative to the original file location or a full asset path. + //! This will usually include multiple source dependencies and a single job dependency, but will include only source dependencies if the file is not found. + //! Note the AssetBuilderSDK::JobDependency::m_platformIdentifier will not be set by this function. The calling code must set this value before passing back + //! to the AssetBuilderSDK::CreateJobsResponse. + void AddPossibleDependencies( + FindPassReferenceAssetParams& params, + AssetBuilderSDK::CreateJobsResponse& response, + AssetBuilderSDK::JobDescriptor& job) + { + bool dependencyFileFound = false; + + AZStd::vector possibleDependencies = RPI::AssetUtils::GetPossibleDepenencyPaths(params.passAssetSourceFile, params.dependencySourceFile); + for (auto& file : possibleDependencies) { - response.m_result = AssetBuilderSDK::CreateJobsResultCode::ShuttingDown; - return; + AssetBuilderSDK::SourceFileDependency sourceFileDependency; + sourceFileDependency.m_sourceFileDependencyPath = file; + response.m_sourceFileDependencyList.push_back(sourceFileDependency); + + // The first path found is the highest priority, and will have a job dependency, as this is the one + // the builder will actually use + if (!dependencyFileFound) + { + AZ::Data::AssetInfo sourceInfo; + AZStd::string watchFolder; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(dependencyFileFound, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetSourceInfoBySourcePath, file.c_str(), sourceInfo, watchFolder); + + if (dependencyFileFound) + { + AssetBuilderSDK::JobDependency jobDependency; + jobDependency.m_jobKey = params.jobKey; + jobDependency.m_type = AssetBuilderSDK::JobDependencyType::Order; + jobDependency.m_sourceFile.m_sourceFileDependencyPath = file; + job.m_jobDependencyList.push_back(jobDependency); + } + } } - - for (const AssetBuilderSDK::PlatformInfo& platformInfo : request.m_enabledPlatforms) - { - AssetBuilderSDK::JobDescriptor job; - job.m_jobKey = PassBuilderJobKey; - job.SetPlatformIdentifier(platformInfo.m_identifier.c_str()); - - // Passes are a critical part of the rendering system - job.m_critical = true; - - response.m_createJobOutputs.push_back(job); - } - - response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success; } // Helper function to find all assetId's and object references - bool PassBuilder::FindPassReferencedAssets(void* objectPtr, Uuid passAssetUuid, SerializeContext* context, AZStd::unordered_set &referencedAssetList) const + bool FindPassReferencedAssets(FindPassReferenceAssetParams& params, + AZStd::unordered_set& referencedAssetList, + AssetBuilderSDK::CreateJobsResponse& response, + AssetBuilderSDK::JobDescriptor& job, + bool jobCreationPhase) { SerializeContext::ErrorHandler errorLogger; errorLogger.Reset(); - + bool foundProblems = false; // This callback will check whether the given element is an asset reference. If so, it will add it to the list of asset references @@ -103,26 +134,34 @@ namespace AZ if (classData->m_typeId == azrtti_typeid()) { AssetReference* assetReference = reinterpret_cast(ptr); - + // If the asset id isn't already provided, get it using the source file path if (!assetReference->m_assetId.IsValid() && !assetReference->m_filePath.empty()) { - AZStd::string path = assetReference->m_filePath; + const AZStd::string& path = assetReference->m_filePath; uint32_t subId = 0; - auto assetIdOutcome = AssetUtils::MakeAssetId(path, subId); - - if (assetIdOutcome) + if (jobCreationPhase) { - assetReference->m_assetId = assetIdOutcome.GetValue(); + params.dependencySourceFile = path; + AddPossibleDependencies(params, response, job); } - else + else // Process Job Phase { - AZ_Error(PassBuilderName, false, "Could not get AssetId for [%s]", assetReference->m_filePath.c_str()); - foundProblems = true; + auto assetIdOutcome = AssetUtils::MakeAssetId(path, subId); + + if (assetIdOutcome) + { + assetReference->m_assetId = assetIdOutcome.GetValue(); + } + else + { + AZ_Error(PassBuilderName, false, "Could not get AssetId for [%s]", assetReference->m_filePath.c_str()); + foundProblems = true; + } } } - + // If the asset ID is valid, add it as a dependency if (assetReference->m_assetId.IsValid()) { @@ -136,16 +175,16 @@ namespace AZ SerializeContext::EnumerateInstanceCallContext callContext( AZStd::move(beginCallback), nullptr, - context, + params.serializeContext, SerializeContext::ENUM_ACCESS_FOR_READ, &errorLogger ); // Recursively iterate over all elements in the object to find asset references with the above callback - context->EnumerateInstance( + params.serializeContext->EnumerateInstance( &callContext - , objectPtr - , passAssetUuid + , params.passAssetObject + , params.passAssetUuid , nullptr , nullptr ); @@ -153,6 +192,73 @@ namespace AZ return !foundProblems; } + // --- Code related to dependency shader asset handling --- + + void PassBuilder::CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response) const + { + if (m_isShuttingDown) + { + response.m_result = AssetBuilderSDK::CreateJobsResultCode::ShuttingDown; + return; + } + + AssetBuilderSDK::JobDescriptor job; + + // Get serialization context + SerializeContext* serializeContext = nullptr; + ComponentApplicationBus::BroadcastResult(serializeContext, &ComponentApplicationBus::Events::GetSerializeContext); + if (!serializeContext) + { + AZ_Assert(false, "No serialize context"); + return; + } + + // Load PassAsset + AZStd::string fullPath; + AzFramework::StringFunc::Path::ConstructFull(request.m_watchFolder.c_str(), request.m_sourceFile.c_str(), fullPath, true); + + PassAsset passAsset; + AZ::Outcome loadResult = JsonSerializationUtils::LoadObjectFromFile(passAsset, fullPath); + + if (!loadResult.IsSuccess()) + { + AZ_Error(PassBuilderName, false, "Failed to load pass asset [%s]", request.m_sourceFile.c_str()); + AZ_Error(PassBuilderName, false, "Loading issues: %s", loadResult.GetError().data()); + return; + } + + // Find all Asset IDs we depend on + AZStd::unordered_set dependentList; + Uuid passAssetUuid = AzTypeInfo::Uuid(); + + FindPassReferenceAssetParams params; + params.passAssetObject = &passAsset; + params.passAssetSourceFile = request.m_sourceFile; + params.passAssetUuid = passAssetUuid; + params.serializeContext = serializeContext; + params.jobKey = "Shader Asset"; + + if (!FindPassReferencedAssets(params, dependentList, response, job, true)) + { + return; + } + + for (const AssetBuilderSDK::PlatformInfo& platformInfo : request.m_enabledPlatforms) + { + job.m_jobKey = PassBuilderJobKey; + job.SetPlatformIdentifier(platformInfo.m_identifier.c_str()); + + // Passes are a critical part of the rendering system + job.m_critical = true; + + response.m_createJobOutputs.push_back(job); + } + + response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success; + } + + + void PassBuilder::ProcessJob(const AssetBuilderSDK::ProcessJobRequest& request, AssetBuilderSDK::ProcessJobResponse& response) const { // Handle job cancellation and shutdown cases @@ -164,9 +270,9 @@ namespace AZ } // Get serialization context - SerializeContext* context = nullptr; - ComponentApplicationBus::BroadcastResult(context, &ComponentApplicationBus::Events::GetSerializeContext); - if (!context) + SerializeContext* serializeContext = nullptr; + ComponentApplicationBus::BroadcastResult(serializeContext, &ComponentApplicationBus::Events::GetSerializeContext); + if (!serializeContext) { AZ_Assert(false, "No serialize context"); return; @@ -186,7 +292,18 @@ namespace AZ // Find all Asset IDs we depend on AZStd::unordered_set dependentList; Uuid passAssetUuid = AzTypeInfo::Uuid(); - if (!FindPassReferencedAssets(&passAsset, passAssetUuid, context, dependentList)) + + FindPassReferenceAssetParams params; + params.passAssetObject = &passAsset; + params.passAssetSourceFile = request.m_sourceFile; + params.passAssetUuid = passAssetUuid; + params.serializeContext = serializeContext; + params.jobKey = "Shader Asset"; + + AssetBuilderSDK::CreateJobsResponse dummyResponse; + AssetBuilderSDK::JobDescriptor dummyJob; + + if (!FindPassReferencedAssets(params, dependentList, dummyResponse, dummyJob, false)) { return; } @@ -198,7 +315,7 @@ namespace AZ AzFramework::StringFunc::Path::ConstructFull(request.m_tempDirPath.c_str(), destFileName.c_str(), destPath, true); // Save the asset to binary format for production - bool result = Utils::SaveObjectToFile(destPath, DataStream::ST_BINARY, &passAsset, passAssetUuid, context); + bool result = Utils::SaveObjectToFile(destPath, DataStream::ST_BINARY, &passAsset, passAssetUuid, serializeContext); if (result == false) { AZ_Error(PassBuilderName, false, "Failed to save asset to %s", destPath.c_str()); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.h b/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.h index 6130ae8edc..8c159efc56 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.h +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.h @@ -37,7 +37,6 @@ namespace AZ void RegisterBuilder(); private: - bool FindPassReferencedAssets(void* objectPtr, Uuid passAssetUuid, SerializeContext* context, AZStd::unordered_set &referencedAssetList) const; bool m_isShuttingDown = false; }; From 635b9686c6915803d472a56740b1c1cf028c417d Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Mon, 9 Aug 2021 11:18:38 -0700 Subject: [PATCH 06/70] [redcode/crythread-2nd-pass] removed CrySimpleThread and related code Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Code/Legacy/CryCommon/CryThread.h | 75 --- .../Legacy/CryCommon/CryThreadImpl_pthreads.h | 7 - Code/Legacy/CryCommon/CryThreadImpl_windows.h | 51 -- Code/Legacy/CryCommon/CryThread_pthreads.h | 440 ------------------ Code/Legacy/CryCommon/CryThread_windows.h | 206 -------- 5 files changed, 779 deletions(-) diff --git a/Code/Legacy/CryCommon/CryThread.h b/Code/Legacy/CryCommon/CryThread.h index b7b6a3adfd..fcd7be16ba 100644 --- a/Code/Legacy/CryCommon/CryThread.h +++ b/Code/Legacy/CryCommon/CryThread.h @@ -85,81 +85,6 @@ public: ////////////////////////////////////////////////////////////////////////// typedef CryAutoLock CryAutoCriticalSection; -///////////////////////////////////////////////////////////////////////////// -// -// Threads. - -// Base class for runnable objects. -// -// A runnable is an object with a Run() and a Cancel() method. The Run() -// method should perform the runnable's job. The Cancel() method may be -// called by another thread requesting early termination of the Run() method. -// The runnable may ignore the Cancel() call, the default implementation of -// Cancel() does nothing. -class CryRunnable -{ -public: - virtual ~CryRunnable() { } - virtual void Run() = 0; - virtual void Cancel() { } -}; - -// Class holding information about a thread. -// -// A reference to the thread information can be obtained by calling GetInfo() -// on the CrySimpleThread (or derived class) instance. -// -// NOTE: -// If the code is compiled with NO_THREADINFO defined, then the GetInfo() -// method will return a reference to a static dummy instance of this -// structure. It is currently undecided if NO_THREADINFO will be defined for -// release builds! - -struct CryThreadInfo -{ - // The symbolic name of the thread. - // - // You may set this name directly or through the SetName() method of - // CrySimpleThread (or derived class). - AZStd::string m_Name; - - - // A thread identification number. - // The number is unique but architecture specific. Do not assume anything - // about that number except for being unique. - // - // This field is filled when the thread is started (i.e. before the Run() - // method or thread routine is called). It is advised that you do not - // change this number manually. - uint32 m_ID; -}; - -// Simple thread class. -// -// CrySimpleThread is a simple wrapper around a system thread providing -// nothing but system-level functionality of a thread. There are two typical -// ways to use a simple thread: -// -// 1. Derive from the CrySimpleThread class and provide an implementation of -// the Run() (and optionally Cancel()) methods. -// 2. Specify a runnable object when the thread is started. The default -// runnable type is CryRunnable. -// -// The Runnable class specfied as the template argument must provide Run() -// and Cancel() methods compatible with the following signatures: -// -// void Runnable::Run(); -// void Runnable::Cancel(); -// -// If the Runnable does not support cancellation, then the Cancel() method -// should do nothing. -// -// The same instance of CrySimpleThread may be used for multiple thread -// executions /in sequence/, i.e. it is valid to re-start the thread by -// calling Start() after the thread has been joined by calling WaitForThread(). -template -class CrySimpleThread; - /////////////////////////////////////////////////////////////////////////////// // Include architecture specific code. #if AZ_LEGACY_CRYCOMMON_TRAIT_USE_PTHREADS diff --git a/Code/Legacy/CryCommon/CryThreadImpl_pthreads.h b/Code/Legacy/CryCommon/CryThreadImpl_pthreads.h index c94d4fca90..358d8f962f 100644 --- a/Code/Legacy/CryCommon/CryThreadImpl_pthreads.h +++ b/Code/Legacy/CryCommon/CryThreadImpl_pthreads.h @@ -14,13 +14,6 @@ #include "CryThread_pthreads.h" -#if PLATFORM_SUPPORTS_THREADLOCAL -THREADLOCAL CrySimpleThreadSelf -* CrySimpleThreadSelf::m_Self = NULL; -#else -TLS_DEFINE(CrySimpleThreadSelf*, g_CrySimpleThreadSelf) -#endif - ////////////////////////////////////////////////////////////////////////// // CryEvent(Timed) implementation diff --git a/Code/Legacy/CryCommon/CryThreadImpl_windows.h b/Code/Legacy/CryCommon/CryThreadImpl_windows.h index 5cf970414d..9d636fd41a 100644 --- a/Code/Legacy/CryCommon/CryThreadImpl_windows.h +++ b/Code/Legacy/CryCommon/CryThreadImpl_windows.h @@ -12,16 +12,6 @@ #include #include // for CreateSemaphore -struct SThreadNameDesc -{ - DWORD dwType; - LPCSTR szName; - DWORD dwThreadID; - DWORD dwFlags; -}; - -THREADLOCAL CrySimpleThreadSelf* CrySimpleThreadSelf::m_Self = NULL; - ////////////////////////////////////////////////////////////////////////// CryEvent::CryEvent() { @@ -302,44 +292,3 @@ void CryFastSemaphore::Release() m_Semaphore.Release(); } } - -////////////////////////////////////////////////////////////////////////// -CrySimpleThreadSelf::CrySimpleThreadSelf() - : m_thread(NULL) - , m_threadId(0) -{ -} - -////////////////////////////////////////////////////////////////////////// -void CrySimpleThreadSelf::WaitForThread() -{ - assert(m_thread); - PREFAST_ASSUME(m_thread); - if (GetCurrentThreadId() != m_threadId) - { - WaitForSingleObject((HANDLE)m_thread, INFINITE); - } -} - -CrySimpleThreadSelf::~CrySimpleThreadSelf() -{ - if (m_thread) - { - CloseHandle(m_thread); - } -} - -void CrySimpleThreadSelf::StartThread(unsigned (__stdcall * func)(void*), void* argList) -{ -#if defined(AZ_RESTRICTED_PLATFORM) - #include AZ_RESTRICTED_FILE(CryThreadImpl_windows_h) -#endif -#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) -#undef AZ_RESTRICTED_SECTION_IMPLEMENTED -#else - m_thread = (void*)_beginthreadex(NULL, 0, func, argList, CREATE_SUSPENDED, &m_threadId); -#endif - assert(m_thread); - PREFAST_ASSUME(m_thread); - ResumeThread((HANDLE)m_thread); -} diff --git a/Code/Legacy/CryCommon/CryThread_pthreads.h b/Code/Legacy/CryCommon/CryThread_pthreads.h index 72b29344ec..9102c12c38 100644 --- a/Code/Legacy/CryCommon/CryThread_pthreads.h +++ b/Code/Legacy/CryCommon/CryThread_pthreads.h @@ -653,444 +653,4 @@ private: typedef CryEventTimed CryEvent; -#if !PLATFORM_SUPPORTS_THREADLOCAL -TLS_DECLARE(class CrySimpleThreadSelf*, g_CrySimpleThreadSelf); -#endif - -class CrySimpleThreadSelf -{ -protected: -#if PLATFORM_SUPPORTS_THREADLOCAL - - static CrySimpleThreadSelf* GetSelf() - { - return m_Self; - } - - static void SetSelf(CrySimpleThreadSelf* pSelf) - { - m_Self = pSelf; - } -private: - static THREADLOCAL CrySimpleThreadSelf* m_Self; - -#else - - static CrySimpleThreadSelf* GetSelf() - { - return TLS_GET(CrySimpleThreadSelf*, g_CrySimpleThreadSelf); - } - - static void SetSelf(CrySimpleThreadSelf* pSelf) - { - TLS_SET(g_CrySimpleThreadSelf, pSelf); - } - -#endif -}; - -template -class CrySimpleThread - : public CryRunnable - , protected CrySimpleThreadSelf -{ -public: - typedef void (* ThreadFunction)(void*); - typedef CryRunnable RunnableT; - - const volatile bool& GetStartedState() const { return m_bIsStarted; } - -private: -#if !defined(NO_THREADINFO) - CryThreadInfo m_Info; -#endif - pthread_t m_ThreadID; - unsigned m_CpuMask; - Runnable* m_Runnable; - struct - { - ThreadFunction m_ThreadFunction; - void* m_ThreadParameter; - } m_ThreadFunction; - volatile bool m_bIsStarted; - volatile bool m_bIsRunning; - -protected: - virtual void Terminate() - { - // This method must be empty. - // Derived classes overriding Terminate() are not required to call this - // method. - } - -private: -#if !defined(NO_THREADINFO) - static void SetThreadInfo(CrySimpleThread* self) - { - pthread_t thread = pthread_self(); - self->m_Info.m_ID = (uint32)(TRUNCATE_PTR)thread; -#if defined(APPLE) - pthread_setname_np(self->m_Info.m_Name.c_str()); -#endif - } -#else - static void SetThreadInfo(CrySimpleThread* self) { } -#endif - - static void* PthreadRunRunnable(void* thisPtr) - { - CrySimpleThread* const self = (CrySimpleThread*)thisPtr; - SetSelf(self); - self->m_bIsStarted = true; - self->m_bIsRunning = true; - SetThreadInfo(self); - self->m_Runnable->Run(); - self->m_bIsRunning = false; - self->Terminate(); - SetSelf(NULL); - return NULL; - } - - static void* PthreadRunThis(void* thisPtr) - { - CrySimpleThread* const self = (CrySimpleThread*)thisPtr; - SetSelf(self); - self->m_bIsStarted = true; - self->m_bIsRunning = true; - SetThreadInfo(self); - self->Run(); - self->m_bIsRunning = false; - self->Terminate(); - SetSelf(NULL); - return NULL; - } - - CrySimpleThread(const CrySimpleThread&); - void operator = (const CrySimpleThread&); - -public: - CrySimpleThread() - : m_CpuMask(0) - , m_bIsStarted(false) - , m_bIsRunning(false) - { - m_ThreadFunction.m_ThreadFunction = NULL; - m_ThreadFunction.m_ThreadParameter = NULL; -#if !defined(NO_THREADINFO) - m_Info.m_Name = ""; - m_Info.m_ID = 0; -#endif - memset(&m_ThreadID, 0, sizeof m_ThreadID); - m_Runnable = NULL; - } - - virtual ~CrySimpleThread() - { - if (IsStarted()) - { - // Note: We don't want to cache a pointer to ISystem and/or ILog to - // gain more freedom on when the threading classes are used (e.g. - // threads may be started very early in the initialization). - ISystem* pSystem = GetISystem(); - ILog* pLog = NULL; - if (pSystem != NULL) - { - pLog = pSystem->GetILog(); - } - if (pLog != NULL) - { - pLog->LogError("Runaway thread %s", GetName()); - } - Cancel(); - WaitForThread(); - } - } - -#if !defined(NO_THREADINFO) - CryThreadInfo& GetInfo() { return m_Info; } - const char* GetName() - { - return m_Info.m_Name.c_str(); - } - - // Set the name of the called thread. - // - // WIN32: - // If the thread is started, then the VC debugger is informed about the new - // thread name. If the thread is not started, then the VC debugger will be - // informed lated when the thread is started through one of the Start() - // methods. - // - // If the parameter Name is NULL, then the name of the thread is kept - // unchanged. This may be used to sent the current thread name to the VC - // debugger. - void SetName(const char* Name) - { - if (Name != NULL) - { - if (m_ThreadID) - { - RegisterThreadName(m_ThreadID, Name); - } - m_Info.m_Name = Name; - } -#if defined(WIN32) - if (IsStarted()) - { - // The VC debugger gets the information about a thread's name through - // the exception 0x406D1388. - struct - { - DWORD Type; - const char* Name; - DWORD ID; - DWORD Flags; - } Info = { 0x1000, NULL, 0, 0 }; - Info.ID = (DWORD)m_Info.m_ID; - __try - { - RaiseException( - 0x406D1388, 0, sizeof Info / sizeof(DWORD), (ULONG_PTR*)&Info); - } - __except (EXCEPTION_CONTINUE_EXECUTION) - { - } - } -#endif - } -#else -#if !defined(NO_THREADINFO) - CryThreadInfo& GetInfo() - { - static CryThreadInfo dummyInfo = { "", 0 }; - return dummyInfo; - } -#endif - const char* GetName() { return ""; } - void SetName(const char* Name) { } -#endif - - virtual void Run() - { - // This Run() implementation supports the void StartFunction() method. - // However, code using this class (or derived classes) should eventually - // be refactored to use one of the other Start() methods. This code will - // be removed some day and the default implementation of Run() will be - // empty. - if (m_ThreadFunction.m_ThreadFunction != NULL) - { - m_ThreadFunction.m_ThreadFunction(m_ThreadFunction.m_ThreadParameter); - } - } - - // Cancel the running thread. - // - // If the thread class is implemented as a derived class of CrySimpleThread, - // then the derived class should provide an appropriate implementation for - // this method. Calling the base class implementation is _not_ required. - // - // If the thread was started by specifying a Runnable (template argument), - // then the Cancel() call is passed on to the specified runnable. - // - // If the thread was started using the StartFunction() method, then the - // caller must find other means to inform the thread about the cancellation - // request. - virtual void Cancel() - { - if (IsStarted() && m_Runnable != NULL) - { - UnRegisterThreadName(m_ThreadID); - m_Runnable->Cancel(); - } - } - - virtual void Start(Runnable& runnable, unsigned cpuMask = 0, const char* name = NULL, int32 StackSize = (SIMPLE_THREAD_STACK_SIZE_KB * 1024)) - { -#if defined(LARGE_THREAD_STACK) - StackSize *= 4;//debug code needs a lot more than profile -#endif - assert(m_ThreadID == 0); - pthread_attr_t threadAttr; - pthread_attr_init(&threadAttr); - pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_JOINABLE); - pthread_attr_setstacksize(&threadAttr, StackSize); - if (name) - { - this->m_Info.m_Name = name; - } -#if CRYTHREAD_PTHREADS_H_TRAIT_SET_THREAD_NAME - threadAttr.name = (char*)name; -#endif - m_CpuMask = cpuMask; -#if defined(PTHREAD_NPTL) - if (cpuMask != ~0 && cpuMask != 0) - { - cpu_set_t cpuSet; - CPU_ZERO(&cpuSet); - for (int cpu = 0; cpu < sizeof(cpuMask) * 8; ++cpu) - { - if (cpuMask & (1 << cpu)) - { - CPU_SET(cpu, &cpuSet); - } - } - pthread_attr_setaffinity_np(&threadAttr, sizeof cpuSet, &cpuSet); - } -#elif defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION CRYTHREAD_PTHREADS_H_SECTION_START_RUNNABLE - #include AZ_RESTRICTED_FILE(CryThread_pthreads_h) -#endif - m_Runnable = &runnable; - int err = pthread_create( - &m_ThreadID, - &threadAttr, - PthreadRunRunnable, - this); - pthread_attr_destroy(&threadAttr); - RegisterThreadName(m_ThreadID, name); -#if defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION CRYTHREAD_PTHREADS_H_SECTION_START_RUNNABLE_CPUMASK_POSTCREATE - #include AZ_RESTRICTED_FILE(CryThread_pthreads_h) -#endif - assert(err == 0); - } - - virtual void Start(unsigned cpuMask = 0, const char* name = NULL, int32 Priority = THREAD_PRIORITY_NORMAL, int32 StackSize = (SIMPLE_THREAD_STACK_SIZE_KB * 1024)) - { -#if defined(LARGE_THREAD_STACK) - StackSize *= 4;//debug code needs a lot more than profile -#endif - assert(m_ThreadID == 0); - pthread_attr_t threadAttr; - sched_param schedParam; - pthread_attr_init(&threadAttr); - pthread_attr_getschedparam(&threadAttr, &schedParam); - schedParam.sched_priority = Priority; - pthread_attr_setschedparam(&threadAttr, &schedParam); - pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_JOINABLE); - pthread_attr_setstacksize(&threadAttr, StackSize); - if (name) - { - this->m_Info.m_Name = name; - } -#if CRYTHREAD_PTHREADS_H_TRAIT_SET_THREAD_NAME - threadAttr.name = (char*)name; -#endif - m_CpuMask = cpuMask; -#if defined(PTHREAD_NPTL) - if (cpuMask != ~0 && cpuMask != 0) - { - cpu_set_t cpuSet; - CPU_ZERO(&cpuSet); - for (int cpu = 0; cpu < sizeof(cpuMask) * 8; ++cpu) - { - if (cpuMask & (1 << cpu)) - { - CPU_SET(cpu, &cpuSet); - } - } - pthread_attr_setaffinity_np(&threadAttr, sizeof cpuSet, &cpuSet); - } -#elif defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION CRYTHREAD_PTHREADS_H_SECTION_START_CPUMASK - #include AZ_RESTRICTED_FILE(CryThread_pthreads_h) -#endif - int err = pthread_create( - &m_ThreadID, - &threadAttr, - PthreadRunThis, - this); - pthread_attr_destroy(&threadAttr); - RegisterThreadName(m_ThreadID, name); -#if defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION CRYTHREAD_PTHREADS_H_SECTION_START_CPUMASK_POSTCREATE - #include AZ_RESTRICTED_FILE(CryThread_pthreads_h) -#endif - assert(err == 0); - } - - void StartFunction( - ThreadFunction threadFunction, - void* threadParameter = NULL, - unsigned cpuMask = 0 - ) - { - m_ThreadFunction.m_ThreadFunction = threadFunction; - m_ThreadFunction.m_ThreadParameter = threadParameter; - Start(cpuMask); - } - - static CrySimpleThread* Self() - { - return reinterpret_cast*>(GetSelf()); - } - - void Exit() - { - assert(m_ThreadID == pthread_self()); - m_bIsRunning = false; - Terminate(); - SetSelf(NULL); - pthread_exit(NULL); - UnRegisterThreadName(m_ThreadID); - } - - void WaitForThread() - { - if (pthread_self() != m_ThreadID) - { - int err = pthread_join(m_ThreadID, NULL); - assert(err == 0); - } - m_bIsStarted = false; - memset(&m_ThreadID, 0, sizeof m_ThreadID); - } - - unsigned SetCpuMask(unsigned cpuMask) - { - int oldCpuMask = m_CpuMask; - if (cpuMask == m_CpuMask) - { - return oldCpuMask; - } - m_CpuMask = cpuMask; -#if defined(PTHREAD_NPTL) - cpu_set_t cpuSet; - CPU_ZERO(&cpuSet); - if (cpuMask != ~0 && cpuMask != 0) - { - for (int cpu = 0; cpu < sizeof(cpuMask) * 8; ++cpu) - { - if (cpuMask & (1 << cpu)) - { - CPU_SET(cpu, &cpuSet); - } - } - else - { - CPU_ZERO(&cpuSet); - for (int cpu = 0; i < sizeof(cpuSet) * 8; ++cpu) - { - CPU_SET(cpu, &cpuSet); - } - } - pthread_attr_setaffinity_np(&threadAttr, sizeof cpuSet, &cpuSet); -#elif defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION CRYTHREAD_PTHREADS_H_SECTION_SETCPUMASK - #include AZ_RESTRICTED_FILE(CryThread_pthreads_h) -#endif - return oldCpuMask; - } - - unsigned GetCpuMask() { return m_CpuMask; } - - void Stop() - { - m_bIsStarted = false; - } - - bool IsStarted() const { return m_bIsStarted; } - bool IsRunning() const { return m_bIsRunning; } - }; - #include "MemoryAccess.h" diff --git a/Code/Legacy/CryCommon/CryThread_windows.h b/Code/Legacy/CryCommon/CryThread_windows.h index cc09cc530b..87147549f7 100644 --- a/Code/Legacy/CryCommon/CryThread_windows.h +++ b/Code/Legacy/CryCommon/CryThread_windows.h @@ -179,209 +179,3 @@ private: CrySemaphore m_Semaphore; volatile int32 m_nCounter; }; - -////////////////////////////////////////////////////////////////////////// -class CrySimpleThreadSelf -{ -public: - CrySimpleThreadSelf(); - void WaitForThread(); - virtual ~CrySimpleThreadSelf(); -protected: - void StartThread(unsigned (__stdcall * func)(void*), void* argList); - static THREADLOCAL CrySimpleThreadSelf* m_Self; -private: - CrySimpleThreadSelf(const CrySimpleThreadSelf&); - CrySimpleThreadSelf& operator = (const CrySimpleThreadSelf&); -protected: - void* m_thread; - uint32 m_threadId; -}; - -template -class CrySimpleThread - : public CryRunnable - , public CrySimpleThreadSelf -{ -public: - typedef void (* ThreadFunction)(void*); - typedef CryRunnable RunnableT; - - void SetName(const char* Name) - { - m_name = Name; - } - const char* GetName() { return m_name; } - - const volatile bool& GetStartedState() const { return m_bIsStarted; } - -private: - Runnable* m_Runnable; - struct - { - ThreadFunction m_ThreadFunction; - void* m_ThreadParameter; - } m_ThreadFunction; - volatile bool m_bIsStarted; - volatile bool m_bIsRunning; - volatile bool m_bCreatedThread; - string m_name; - -protected: - virtual void Terminate() - { - // This method must be empty. - // Derived classes overriding Terminate() are not required to call this - // method. - } - -private: - static unsigned __stdcall RunRunnable(void* thisPtr) - { -#if defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION CRYTHREAD_WINDOWS_H_SECTION_1 - #include AZ_RESTRICTED_FILE(CryThread_windows_h) -#endif - CrySimpleThread* const self = (CrySimpleThread*)thisPtr; - self->m_bIsStarted = true; - self->m_bIsRunning = true; - - self->m_Runnable->Run(); - self->m_bIsRunning = false; - self->m_bCreatedThread = false; - self->Terminate(); - return 0; - } - - static unsigned __stdcall RunThis(void* thisPtr) - { -#if defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION CRYTHREAD_WINDOWS_H_SECTION_2 - #include AZ_RESTRICTED_FILE(CryThread_windows_h) -#endif - CrySimpleThread* const self = (CrySimpleThread*)thisPtr; - self->m_bIsStarted = true; - self->m_bIsRunning = true; - - self->Run(); - self->m_bIsRunning = false; - self->m_bCreatedThread = false; - self->Terminate(); - return 0; - } - - CrySimpleThread(const CrySimpleThread&); - void operator = (const CrySimpleThread&); - -public: - CrySimpleThread() - : m_bIsStarted(false) - , m_bIsRunning(false) - , m_bCreatedThread(false) - { - m_thread = NULL; - m_Runnable = NULL; - } - void* GetHandle() { return m_thread; } - - virtual ~CrySimpleThread() - { - if (IsStarted()) - { - if (gEnv && gEnv->pLog) - { - gEnv->pLog->LogError("Runaway thread %p '%s'", m_thread, m_name.c_str()); - } - } - - if (m_bCreatedThread) - { - Cancel(); - WaitForThread(); - } - } - - virtual void Run() - { - // This Run() implementation supports the void StartFunction() method. - // However, code using this class (or derived classes) should eventually - // be refactored to use one of the other Start() methods. This code will - // be removed some day and the default implementation of Run() will be - // empty. - if (m_ThreadFunction.m_ThreadFunction != NULL) - { - m_ThreadFunction.m_ThreadFunction(m_ThreadFunction.m_ThreadParameter); - } - } - - // Cancel the running thread. - // - // If the thread class is implemented as a derived class of CrySimpleThread, - // then the derived class should provide an appropriate implementation for - // this method. Calling the base class implementation is _not_ required. - // - // If the thread was started by specifying a Runnable (template argument), - // then the Cancel() call is passed on to the specified runnable. - // - // If the thread was started using the StartFunction() method, then the - // caller must find other means to inform the thread about the cancellation - // request. - virtual void Cancel() - { - if (IsStarted() && m_Runnable != NULL) - { - m_Runnable->Cancel(); - } - } - - virtual void Start(Runnable& runnable, [[maybe_unused]] unsigned cpuMask = 0, const char* = NULL, int32 = 0) - { - if (m_bCreatedThread) - { - // Don't start thread more than once! - return; - } - m_Runnable = &runnable; - m_bCreatedThread = true; - StartThread(RunRunnable, this); - } - - virtual void Start([[maybe_unused]] unsigned cpuMask = 0, const char* = NULL, int32 = 0, int32 = 0) - { - if (m_bCreatedThread) - { - // Don't start thread more than once! - return; - } - m_bCreatedThread = true; - StartThread(RunThis, this); - } - - void StartFunction( - ThreadFunction threadFunction, - void* threadParameter = NULL - ) - { - m_ThreadFunction.m_ThreadFunction = threadFunction; - m_ThreadFunction.m_ThreadParameter = threadParameter; - Start(); - } - - static CrySimpleThread* Self() - { - return reinterpret_cast*>(m_Self); - } - - void Exit() - { - assert(!"implemented"); - } - - void Stop() - { - m_bIsStarted = false; - } - - bool IsStarted() const { return m_bIsStarted; } - bool IsRunning() const { return m_bIsRunning; } -}; From 6a2d5cd370ae0e35c47188531a3a7eb6d2197e1f Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Mon, 9 Aug 2021 12:22:03 -0700 Subject: [PATCH 07/70] [redcode/crythread-2nd-pass] removed Cry-TLS macros from platform.h Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Code/Legacy/CryCommon/platform.h | 54 -------------------------------- 1 file changed, 54 deletions(-) diff --git a/Code/Legacy/CryCommon/platform.h b/Code/Legacy/CryCommon/platform.h index 6aad8dd043..851da316e0 100644 --- a/Code/Legacy/CryCommon/platform.h +++ b/Code/Legacy/CryCommon/platform.h @@ -277,18 +277,6 @@ #define PRINTF_EMPTY_FORMAT "" #endif -#if defined(IOS) -#define USE_PTHREAD_TLS -#endif - -// Storage class modifier for thread local storage. -// THEADLOCAL should NOT be defined to empty because that creates some -// really hard to find issues. -#if !defined(USE_PTHREAD_TLS) -# define THREADLOCAL AZ_TRAIT_COMPILER_THREAD_LOCAL -#endif //!defined(USE_PTHREAD_TLS) - - ////////////////////////////////////////////////////////////////////////// // define Read Write Barrier macro needed for lockless programming @@ -735,48 +723,6 @@ enum ETriState #define _MS_ALIGN(num) AZ_PUSH_DISABLE_WARNING(4324, "-Wunknown-warning-option") #endif -#if defined(WIN32) || defined(WIN64) -extern "C" { -__declspec(dllimport) unsigned long __stdcall TlsAlloc(); -__declspec(dllimport) void* __stdcall TlsGetValue(unsigned long dwTlsIndex); -__declspec(dllimport) int __stdcall TlsSetValue(unsigned long dwTlsIndex, void* lpTlsValue); -} - - #define TLS_DECLARE(type, var) extern int var##idx; - #define TLS_DEFINE(type, var) \ - int var##idx; \ - struct Init##var { \ - Init##var() { var##idx = TlsAlloc(); } \ - }; \ - Init##var g_init##var; - #define TLS_DEFINE_DEFAULT_VALUE(type, var, value) \ - int var##idx; \ - struct Init##var { \ - Init##var() { var##idx = TlsAlloc(); TlsSetValue(var##idx, reinterpret_cast(value)); } \ - }; \ - Init##var g_init##var; - #define TLS_GET(type, var) (type)TlsGetValue(var##idx) - #define TLS_SET(var, val) TlsSetValue(var##idx, reinterpret_cast(val)) -#elif defined(USE_PTHREAD_TLS) - #define TLS_DECLARE(_TYPE, _VAR) extern SCryPthreadTLS<_TYPE> _VAR##TLSKey; - #define TLS_DEFINE(_TYPE, _VAR) SCryPthreadTLS<_TYPE> _VAR##TLSKey; - #define TLS_DEFINE_DEFAULT_VALUE(_TYPE, _VAR, _DEFAULT) SCryPthreadTLS<_TYPE> _VAR##TLSKey = _DEFAULT; - #define TLS_GET(_TYPE, _VAR) _VAR##TLSKey.Get() - #define TLS_SET(_VAR, _VALUE) _VAR##TLSKey.Set(_VALUE) -#elif defined(THREADLOCAL) - #define TLS_DECLARE(type, var) extern THREADLOCAL type var; -#if defined(LINUX) || defined(MAC) - #define TLS_DEFINE(type, var) THREADLOCAL type var = 0; -#else - #define TLS_DEFINE(type, var) THREADLOCAL type var; -#endif // defined(LINUX) || defined(MAC) - #define TLS_DEFINE_DEFAULT_VALUE(type, var, value) THREADLOCAL type var = value; - #define TLS_GET(type, var) (var) - #define TLS_SET(var, val) (var = (val)) -#else // defined(THREADLOCAL) - #error "There's no support for thread local storage" -#endif - #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION PLATFORM_H_SECTION_13 #include AZ_RESTRICTED_FILE(platform_h) From 2e2bbe80b118e5481a8be0b275ec039cf4ee3a7e Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Mon, 9 Aug 2021 13:19:41 -0700 Subject: [PATCH 08/70] [redcode/crythread-2nd-pass] removed CryEvent types Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- .../Legacy/CryCommon/CryThreadImpl_pthreads.h | 47 ------------------- Code/Legacy/CryCommon/CryThreadImpl_windows.h | 39 --------------- Code/Legacy/CryCommon/CryThread_pthreads.h | 34 -------------- Code/Legacy/CryCommon/CryThread_windows.h | 30 ------------ 4 files changed, 150 deletions(-) diff --git a/Code/Legacy/CryCommon/CryThreadImpl_pthreads.h b/Code/Legacy/CryCommon/CryThreadImpl_pthreads.h index 358d8f962f..38838991a8 100644 --- a/Code/Legacy/CryCommon/CryThreadImpl_pthreads.h +++ b/Code/Legacy/CryCommon/CryThreadImpl_pthreads.h @@ -14,53 +14,6 @@ #include "CryThread_pthreads.h" - -////////////////////////////////////////////////////////////////////////// -// CryEvent(Timed) implementation -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -void CryEventTimed::Reset() -{ - m_lockNotify.Lock(); - m_flag = false; - m_lockNotify.Unlock(); -} - -////////////////////////////////////////////////////////////////////////// -void CryEventTimed::Set() -{ - m_lockNotify.Lock(); - m_flag = true; - m_cond.Notify(); - m_lockNotify.Unlock(); -} - -////////////////////////////////////////////////////////////////////////// -void CryEventTimed::Wait() -{ - m_lockNotify.Lock(); - if (!m_flag) - { - m_cond.Wait(m_lockNotify); - } - m_flag = false; - m_lockNotify.Unlock(); -} - -////////////////////////////////////////////////////////////////////////// -bool CryEventTimed::Wait(const uint32 timeoutMillis) -{ - bool bResult = true; - m_lockNotify.Lock(); - if (!m_flag) - { - bResult = m_cond.TimedWait(m_lockNotify, timeoutMillis); - } - m_flag = false; - m_lockNotify.Unlock(); - return bResult; -} - /////////////////////////////////////////////////////////////////////////////// // CryCriticalSection implementation /////////////////////////////////////////////////////////////////////////////// diff --git a/Code/Legacy/CryCommon/CryThreadImpl_windows.h b/Code/Legacy/CryCommon/CryThreadImpl_windows.h index 9d636fd41a..d81f3b0689 100644 --- a/Code/Legacy/CryCommon/CryThreadImpl_windows.h +++ b/Code/Legacy/CryCommon/CryThreadImpl_windows.h @@ -12,45 +12,6 @@ #include #include // for CreateSemaphore -////////////////////////////////////////////////////////////////////////// -CryEvent::CryEvent() -{ - m_handle = (void*)CreateEvent(NULL, FALSE, FALSE, NULL); -} - -////////////////////////////////////////////////////////////////////////// -CryEvent::~CryEvent() -{ - CloseHandle(m_handle); -} - -////////////////////////////////////////////////////////////////////////// -void CryEvent::Reset() -{ - ResetEvent(m_handle); -} - -////////////////////////////////////////////////////////////////////////// -void CryEvent::Set() -{ - SetEvent(m_handle); -} - -////////////////////////////////////////////////////////////////////////// -void CryEvent::Wait() const -{ - WaitForSingleObject(m_handle, INFINITE); -} - -////////////////////////////////////////////////////////////////////////// -bool CryEvent::Wait(const uint32 timeoutMillis) const -{ - if (WaitForSingleObject(m_handle, timeoutMillis) == WAIT_TIMEOUT) - { - return false; - } - return true; -} ////////////////////////////////////////////////////////////////////////// // CryLock_WinMutex diff --git a/Code/Legacy/CryCommon/CryThread_pthreads.h b/Code/Legacy/CryCommon/CryThread_pthreads.h index 9102c12c38..8dd4bfba6c 100644 --- a/Code/Legacy/CryCommon/CryThread_pthreads.h +++ b/Code/Legacy/CryCommon/CryThread_pthreads.h @@ -619,38 +619,4 @@ struct SCryPthreadTLS { }; - -////////////////////////////////////////////////////////////////////////// -// CryEvent(Timed) represent a synchronization event -////////////////////////////////////////////////////////////////////////// -class CryEventTimed -{ -public: - ILINE CryEventTimed(){m_flag = false; } - ILINE ~CryEventTimed(){} - - // Reset the event to the unsignalled state. - void Reset(); - // Set the event to the signalled state. - void Set(); - // Access a HANDLE to wait on. - void* GetHandle() const { return NULL; }; - // Wait indefinitely for the object to become signalled. - void Wait(); - // Wait, with a time limit, for the object to become signalled. - bool Wait(const uint32 timeoutMillis); - -private: - // Lock for synchronization of notifications. - CryCriticalSection m_lockNotify; -#if defined(LINUX) || defined(APPLE) - CryConditionVariableT< CryLockT > m_cond; -#else - CryConditionVariable m_cond; -#endif - volatile bool m_flag; -}; - -typedef CryEventTimed CryEvent; - #include "MemoryAccess.h" diff --git a/Code/Legacy/CryCommon/CryThread_windows.h b/Code/Legacy/CryCommon/CryThread_windows.h index 87147549f7..68908ab34a 100644 --- a/Code/Legacy/CryCommon/CryThread_windows.h +++ b/Code/Legacy/CryCommon/CryThread_windows.h @@ -17,36 +17,6 @@ #define CRYTHREAD_WINDOWS_H_SECTION_2 2 #endif -////////////////////////////////////////////////////////////////////////// -// CryEvent represent a synchronization event -////////////////////////////////////////////////////////////////////////// -class CryEvent -{ -public: - CryEvent(); - ~CryEvent(); - - // Reset the event to the unsignalled state. - void Reset(); - // Set the event to the signalled state. - void Set(); - // Access a HANDLE to wait on. - void* GetHandle() const { return m_handle; }; - // Wait indefinitely for the object to become signalled. - void Wait() const; - // Wait, with a time limit, for the object to become signalled. - bool Wait(const uint32 timeoutMillis) const; - -private: - CryEvent(const CryEvent&); - CryEvent& operator = (const CryEvent&); - -private: - void* m_handle; -}; - -typedef CryEvent CryEventTimed; - ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// From f47b8b534ba7abb2b24cd6cf29bb0a025c8ce2c3 Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Mon, 9 Aug 2021 14:03:42 -0700 Subject: [PATCH 09/70] [redcode/crythread-2nd-pass] removed unused CryConditionVariable in CryEdit Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Code/Editor/CryEdit.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp index cd1dd4fe47..5a5b17f799 100644 --- a/Code/Editor/CryEdit.cpp +++ b/Code/Editor/CryEdit.cpp @@ -892,7 +892,6 @@ CCrySingleDocTemplate::Confidence CCrySingleDocTemplate::MatchDocType(LPCTSTR lp namespace { CryMutex g_splashScreenStateLock; - CryConditionVariable g_splashScreenStateChange; enum ESplashScreenState { eSplashScreenState_Init, eSplashScreenState_Started, eSplashScreenState_Destroy @@ -932,7 +931,6 @@ void CCryEditApp::ShowSplashScreen(CCryEditApp* app) g_splashScreenState = eSplashScreenState_Started; g_splashScreenStateLock.Unlock(); - g_splashScreenStateChange.Notify(); splashScreen->show(); // Make sure the initial paint of the splash screen occurs so we dont get stuck with a blank window From 2408f7dc37acdb302026743d08ce13238e5ec3a8 Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Mon, 9 Aug 2021 14:49:29 -0700 Subject: [PATCH 10/70] [redcode/crythread-2nd-pass] removed more unused code from CryThread Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Code/Legacy/CryCommon/CryThreadImpl_windows.h | 177 -------- Code/Legacy/CryCommon/CryThread_pthreads.h | 423 ------------------ Code/Legacy/CryCommon/CryThread_windows.h | 56 --- 3 files changed, 656 deletions(-) diff --git a/Code/Legacy/CryCommon/CryThreadImpl_windows.h b/Code/Legacy/CryCommon/CryThreadImpl_windows.h index d81f3b0689..9157bde9bc 100644 --- a/Code/Legacy/CryCommon/CryThreadImpl_windows.h +++ b/Code/Legacy/CryCommon/CryThreadImpl_windows.h @@ -76,180 +76,3 @@ bool CryLock_CritSection::TryLock() { return TryEnterCriticalSection((CRITICAL_SECTION*)&m_cs) != FALSE; } - -////////////////////////////////////////////////////////////////////////// -// most of this is taken from http://www.cs.wustl.edu/~schmidt/win32-cv-1.html -////////////////////////////////////////////////////////////////////////// -CryConditionVariable::CryConditionVariable() -{ - m_waitersCount = 0; - m_wasBroadcast = 0; - m_sema = CreateSemaphore(NULL, 0, 0x7fffffff, NULL); - InitializeCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock); - m_waitersDone = CreateEvent(NULL, FALSE, FALSE, NULL); -} - -////////////////////////////////////////////////////////////////////////// -CryConditionVariable::~CryConditionVariable() -{ - CloseHandle(m_sema); - DeleteCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock); - CloseHandle(m_waitersDone); -} - -////////////////////////////////////////////////////////////////////////// -void CryConditionVariable::Wait(LockType& lock) -{ - EnterCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock); - m_waitersCount++; - LeaveCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock); - - SignalObjectAndWait(lock._get_win32_handle(), m_sema, INFINITE, FALSE); - - EnterCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock); - m_waitersCount--; - bool lastWaiter = m_wasBroadcast && m_waitersCount == 0; - LeaveCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock); - - if (lastWaiter) - { - SignalObjectAndWait(m_waitersDone, lock._get_win32_handle(), INFINITE, FALSE); - } - else - { - WaitForSingleObject(lock._get_win32_handle(), INFINITE); - } -} - -////////////////////////////////////////////////////////////////////////// -bool CryConditionVariable::TimedWait(LockType& lock, uint32 millis) -{ - EnterCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock); - m_waitersCount++; - LeaveCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock); - - bool ok = true; - if (WAIT_TIMEOUT == SignalObjectAndWait(lock._get_win32_handle(), m_sema, millis, FALSE)) - { - ok = false; - } - - EnterCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock); - m_waitersCount--; - bool lastWaiter = m_wasBroadcast && m_waitersCount == 0; - LeaveCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock); - - if (lastWaiter) - { - SignalObjectAndWait(m_waitersDone, lock._get_win32_handle(), INFINITE, FALSE); - } - else - { - WaitForSingleObject(lock._get_win32_handle(), INFINITE); - } - - return ok; -} - -////////////////////////////////////////////////////////////////////////// -void CryConditionVariable::NotifySingle() -{ - EnterCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock); - bool haveWaiters = m_waitersCount > 0; - LeaveCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock); - if (haveWaiters) - { - ReleaseSemaphore(m_sema, 1, 0); - } -} - -////////////////////////////////////////////////////////////////////////// -void CryConditionVariable::Notify() -{ - EnterCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock); - bool haveWaiters = false; - if (m_waitersCount > 0) - { - m_wasBroadcast = 1; - haveWaiters = true; - } - if (haveWaiters) - { - ReleaseSemaphore(m_sema, m_waitersCount, 0); - LeaveCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock); - WaitForSingleObject(m_waitersDone, INFINITE); - m_wasBroadcast = 0; - } - else - { - LeaveCriticalSection((CRITICAL_SECTION*)&m_waitersCountLock); - } -} - -////////////////////////////////////////////////////////////////////////// -CrySemaphore::CrySemaphore(int nMaximumCount, int nInitialCount) -{ - m_Semaphore = (void*)CreateSemaphore(NULL, nInitialCount, nMaximumCount, NULL); -} - -////////////////////////////////////////////////////////////////////////// -CrySemaphore::~CrySemaphore() -{ - CloseHandle((HANDLE)m_Semaphore); -} - -////////////////////////////////////////////////////////////////////////// -void CrySemaphore::Acquire() -{ - WaitForSingleObject((HANDLE)m_Semaphore, INFINITE); -} - -////////////////////////////////////////////////////////////////////////// -void CrySemaphore::Release() -{ - ReleaseSemaphore((HANDLE)m_Semaphore, 1, NULL); -} - -////////////////////////////////////////////////////////////////////////// -CryFastSemaphore::CryFastSemaphore(int nMaximumCount, int nInitialCount) - : m_Semaphore(nMaximumCount) - , m_nCounter(nInitialCount) -{ -} - -////////////////////////////////////////////////////////////////////////// -CryFastSemaphore::~CryFastSemaphore() -{ -} - -////////////////////////////////////////////////////////////////////////// -void CryFastSemaphore::Acquire() -{ - int nCount = ~0; - do - { - nCount = *const_cast(&m_nCounter); - } while (CryInterlockedCompareExchange(alias_cast(&m_nCounter), nCount - 1, nCount) != nCount); - - // if the count would have been 0 or below, go to kernel semaphore - if ((nCount - 1) < 0) - { - m_Semaphore.Acquire(); - } -} - -////////////////////////////////////////////////////////////////////////// -void CryFastSemaphore::Release() -{ - int nCount = ~0; - do - { - nCount = *const_cast(&m_nCounter); - } while (CryInterlockedCompareExchange(alias_cast(&m_nCounter), nCount + 1, nCount) != nCount); - - // wake up kernel semaphore if we have waiter - if (nCount < 0) - { - m_Semaphore.Release(); - } -} diff --git a/Code/Legacy/CryCommon/CryThread_pthreads.h b/Code/Legacy/CryCommon/CryThread_pthreads.h index 8dd4bfba6c..9e04784f3f 100644 --- a/Code/Legacy/CryCommon/CryThread_pthreads.h +++ b/Code/Legacy/CryCommon/CryThread_pthreads.h @@ -48,52 +48,12 @@ #undef AZ_RESTRICTED_SECTION_IMPLEMENTED #endif -#if !defined(RegisterThreadName) - #define RegisterThreadName(id, name) - #define UnRegisterThreadName(id) -#endif - #if defined(APPLE) || defined(ANDROID) // PTHREAD_MUTEX_FAST_NP is only defined by Pthreads-w32, thus not on MAC #define PTHREAD_MUTEX_FAST_NP PTHREAD_MUTEX_NORMAL #endif -// Define LARGE_THREAD_STACK to use larger than normal per-thread stack -#if defined(_DEBUG) && (defined(MAC) || defined(LINUX) || defined(AZ_PLATFORM_IOS)) -#define LARGE_THREAD_STACK -#endif - -#if defined(LINUX) -#undef RegisterThreadName -ILINE void RegisterThreadName(pthread_t id, const char* name) -{ - if ((!name) || (!id)) - { - return; - } - int ret; - // pthread names on linux are limited to 16 char - if (strlen(name) >= 16) - { - char thread_name[16]; - memcpy(thread_name, name, 15); - thread_name[15] = 0; - ret = pthread_setname_np(id, thread_name); - } - else - { - ret = pthread_setname_np(id, name); - } - if (ret != 0) - { - CryLog("Failed to set thread name for %" PRI_THREADID ", name: %s", id, name); - } -} -#endif - #if !defined _CRYTHREAD_HAVE_LOCK -template -class _PthreadCond; template class _PthreadLockBase; @@ -130,8 +90,6 @@ template class _PthreadLock : public _PthreadLockBase { - friend class _PthreadCond; - //#if defined(_DEBUG) public: //#endif @@ -218,9 +176,6 @@ public: #if !defined(LINUX) && !defined(APPLE) #define CRYTHREAD_PTHREADS_H_TRAIT_DEFINE_CRYMUTEX 1 #endif -#if !defined(LINUX) && !defined(APPLE) -#define CRYTHREAD_PTHREADS_H_TRAIT_SET_THREAD_NAME 1 -#endif #endif #if CRYTHREAD_PTHREADS_H_TRAIT_DEFINE_CRYMUTEX @@ -237,386 +192,8 @@ class CryMutex #endif #endif // CRYTHREAD_PTHREADS_TRAIT_DEFINE_CRYMUTEX -template -class _PthreadCond -{ - pthread_cond_t m_Cond; - -public: - _PthreadCond() { pthread_cond_init(&m_Cond, NULL); } - ~_PthreadCond() { pthread_cond_destroy(&m_Cond); } - void Notify() { pthread_cond_broadcast(&m_Cond); } - void NotifySingle() { pthread_cond_signal(&m_Cond); } - void Wait(LockClass& Lock) { pthread_cond_wait(&m_Cond, &Lock.m_Lock); } - bool TimedWait(LockClass& Lock, uint32 milliseconds) - { - struct timeval now; - struct timespec timeout; - int err; - - gettimeofday(&now, NULL); - while (true) - { - timeout.tv_sec = now.tv_sec + milliseconds / 1000; - uint64 nsec = (uint64)now.tv_usec * 1000 + (uint64)milliseconds * 1000000; - if (nsec >= 1000000000) - { - timeout.tv_sec += (long)(nsec / 1000000000); - nsec %= 1000000000; - } - timeout.tv_nsec = (long)nsec; -#if defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION CRYTHREAD_PTHREADS_H_SECTION_PTHREADCOND - #include AZ_RESTRICTED_FILE(CryThread_pthreads_h) -#endif -#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) - #undef AZ_RESTRICTED_SECTION_IMPLEMENTED -#else - err = pthread_cond_timedwait(&m_Cond, &Lock.m_Lock, &timeout); - if (err == EINTR) - { - // Interrupted by a signal. - continue; - } - else if (err == ETIMEDOUT) - { - return false; - } -#endif - else - { - assert(err == 0); - } - break; - } - return true; - } - - // Get the POSIX pthread_cont_t. - // Warning: - // This method will not be available in the Win32 port of CryThread. - pthread_cond_t& Get_pthread_cond_t() { return m_Cond; } -}; - -#if AZ_LEGACY_CRYCOMMON_TRAIT_USE_PTHREADS -template -class CryConditionVariableT - : public _PthreadCond -{ -}; - -#if defined CRYLOCK_HAVE_FASTTLOCK -template<> -class CryConditionVariableT< CryLockT > - : public _PthreadCond< CryLockT > -{ - typedef CryLockT LockClass; - CryConditionVariableT(const CryConditionVariableT&); - CryConditionVariableT& operator = (const CryConditionVariableT&); - -public: - CryConditionVariableT() { } -}; -#endif // CRYLOCK_HAVE_FASTLOCK - -template<> -class CryConditionVariableT< CryLockT > - : public _PthreadCond< CryLockT > -{ - typedef CryLockT LockClass; - CryConditionVariableT(const CryConditionVariableT&); - CryConditionVariableT& operator = (const CryConditionVariableT&); - -public: - CryConditionVariableT() { } -}; - -#if !defined(_CRYTHREAD_CONDLOCK_GLITCH) -typedef CryConditionVariableT< CryLockT > CryConditionVariable; -#else -typedef CryConditionVariableT< CryLockT > CryConditionVariable; -#endif - #define _CRYTHREAD_HAVE_LOCK 1 -#else // LINUX MAC - -#if defined CRYLOCK_HAVE_FASTLOCK -template<> -class CryConditionVariable - : public _PthreadCond< CryLockT > -{ - typedef CryLockT LockClass; - CryConditionVariable(const CryConditionVariable&); - CryConditionVariable& operator = (const CryConditionVariable&); - -public: - CryConditionVariable() { } -}; -#endif // CRYLOCK_HAVE_FASTLOCK - -template<> -class CryConditionVariable - : public _PthreadCond< CryLockT > -{ - typedef CryLockT LockClass; - CryConditionVariable(const CryConditionVariable&); - CryConditionVariable& operator = (const CryConditionVariable&); - -public: - CryConditionVariable() { } -}; - -#define _CRYTHREAD_HAVE_LOCK 1 - -#endif // LINUX MAC #endif // !defined _CRYTHREAD_HAVE_LOCK -////////////////////////////////////////////////////////////////////////// -// Platform independet wrapper for a counting semaphore -class CrySemaphore -{ -public: - CrySemaphore(int nMaximumCount, int nInitialCount = 0); - ~CrySemaphore(); - - void Acquire(); - void Release(); - -private: -#if defined(APPLE) - // Apple only supports named semaphores so have to use sem_open/unlink/sem_close instead - // of sem_open/sem_destroy, passing in this array for the name. - char m_semaphoreName[L_tmpnam]; -#endif - sem_t* m_Semaphore; -}; - -////////////////////////////////////////////////////////////////////////// -inline CrySemaphore::CrySemaphore(int nMaximumCount, int nInitialCount) -{ -#if defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION CRYTHREAD_PTHREADS_H_SECTION_SEMAPHORE_CONSTRUCT - #include AZ_RESTRICTED_FILE(CryThread_pthreads_h) -#endif -#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) - #undef AZ_RESTRICTED_SECTION_IMPLEMENTED -#elif defined(APPLE) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" - tmpnam(m_semaphoreName); -# pragma clang diagnostic pop - m_Semaphore = sem_open(m_semaphoreName, O_CREAT | O_EXCL, 0644, nInitialCount); -#else - m_Semaphore = new sem_t; - sem_init(m_Semaphore, 0, nInitialCount); -#endif -} - -////////////////////////////////////////////////////////////////////////// -inline CrySemaphore::~CrySemaphore() -{ -#if defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION CRYTHREAD_PTHREADS_H_SECTION_SEMAPHORE_DESTROY - #include AZ_RESTRICTED_FILE(CryThread_pthreads_h) -#endif -#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) - #undef AZ_RESTRICTED_SECTION_IMPLEMENTED -#elif defined(APPLE) - sem_close(m_Semaphore); - sem_unlink(m_semaphoreName); -#else - sem_destroy(m_Semaphore); - delete m_Semaphore; -#endif -} - -////////////////////////////////////////////////////////////////////////// -inline void CrySemaphore::Acquire() -{ -#if defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION CRYTHREAD_PTHREADS_H_SECTION_SEMAPHORE_ACQUIRE - #include AZ_RESTRICTED_FILE(CryThread_pthreads_h) -#endif -#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) - #undef AZ_RESTRICTED_SECTION_IMPLEMENTED -#else - while (sem_wait(m_Semaphore) != 0 && errno == EINTR) - { - ; - } -#endif -} - -////////////////////////////////////////////////////////////////////////// -inline void CrySemaphore::Release() -{ -#if defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION CRYTHREAD_PTHREADS_H_SECTION_SEMAPHORE_RELEASE - #include AZ_RESTRICTED_FILE(CryThread_pthreads_h) -#endif -#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) - #undef AZ_RESTRICTED_SECTION_IMPLEMENTED -#else - sem_post(m_Semaphore); -#endif -} - -////////////////////////////////////////////////////////////////////////// -// Platform independet wrapper for a counting semaphore -// except that this version uses C-A-S only until a blocking call is needed -// -> No kernel call if there are object in the semaphore - -class CryFastSemaphore -{ -public: - CryFastSemaphore(int nMaximumCount, int nInitialCount = 0); - ~CryFastSemaphore(); - void Acquire(); - void Release(); - -private: - CrySemaphore m_Semaphore; - volatile int32 m_nCounter; -}; - -////////////////////////////////////////////////////////////////////////// -inline CryFastSemaphore::CryFastSemaphore(int nMaximumCount, int nInitialCount) - : m_Semaphore(nMaximumCount) - , m_nCounter(nInitialCount) -{ -} - -////////////////////////////////////////////////////////////////////////// -inline CryFastSemaphore::~CryFastSemaphore() -{ -} - -///////////////////////////////////////////////////////////////////////// -inline void CryFastSemaphore::Acquire() -{ - int nCount = ~0; - do - { - nCount = *const_cast(&m_nCounter); - } while (CryInterlockedCompareExchange(alias_cast(&m_nCounter), nCount - 1, nCount) != nCount); - - // if the count would have been 0 or below, go to kernel semaphore - if ((nCount - 1) < 0) - { - m_Semaphore.Acquire(); - } -} - -////////////////////////////////////////////////////////////////////////// -inline void CryFastSemaphore::Release() -{ - int nCount = ~0; - do - { - nCount = *const_cast(&m_nCounter); - } while (CryInterlockedCompareExchange(alias_cast(&m_nCounter), nCount + 1, nCount) != nCount); - - // wake up kernel semaphore if we have waiter - if (nCount < 0) - { - m_Semaphore.Release(); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Provide TLS implementation using pthreads for those platforms without __thread -//////////////////////////////////////////////////////////////////////////////// - -struct SCryPthreadTLSBase -{ - SCryPthreadTLSBase(void (*pDestructor)(void*)) - { - pthread_key_create(&m_kKey, pDestructor); - } - - ~SCryPthreadTLSBase() - { - pthread_key_delete(m_kKey); - } - - void* GetSpecific() - { - return pthread_getspecific(m_kKey); - } - - void SetSpecific(const void* pValue) - { - pthread_setspecific(m_kKey, pValue); - } - - pthread_key_t m_kKey; -}; - -template -struct SCryPthreadTLSImpl{}; - -template -struct SCryPthreadTLSImpl - : private SCryPthreadTLSBase -{ - SCryPthreadTLSImpl() - : SCryPthreadTLSBase(NULL) - { - } - - T Get() - { - void* pSpecific(GetSpecific()); - return *reinterpret_cast(&pSpecific); - } - - void Set(const T& kValue) - { - SetSpecific(*reinterpret_cast(&kValue)); - } -}; - -template -struct SCryPthreadTLSImpl - : private SCryPthreadTLSBase -{ - SCryPthreadTLSImpl() - : SCryPthreadTLSBase(&Destroy) - { - } - - T* GetPtr() - { - T* pPtr(static_cast(GetSpecific())); - if (pPtr == NULL) - { - pPtr = new T(); - SetSpecific(pPtr); - } - return pPtr; - } - - static void Destroy(void* pPointer) - { - delete static_cast(pPointer); - } - - const T& Get() - { - return *GetPtr(); - } - - void Set(const T& kValue) - { - *GetPtr() = kValue; - } -}; - -template -struct SCryPthreadTLS - : SCryPthreadTLSImpl -{ -}; - #include "MemoryAccess.h" diff --git a/Code/Legacy/CryCommon/CryThread_windows.h b/Code/Legacy/CryCommon/CryThread_windows.h index 68908ab34a..5f83aa48e0 100644 --- a/Code/Legacy/CryCommon/CryThread_windows.h +++ b/Code/Legacy/CryCommon/CryThread_windows.h @@ -93,59 +93,3 @@ class CryMutex { }; #define _CRYTHREAD_CONDLOCK_GLITCH 1 - -////////////////////////////////////////////////////////////////////////// -class CryConditionVariable -{ -public: - typedef CryMutex LockType; - - CryConditionVariable(); - ~CryConditionVariable(); - void Wait(LockType& lock); - bool TimedWait(LockType& lock, uint32 millis); - void NotifySingle(); - void Notify(); - -private: - CryConditionVariable(const CryConditionVariable&); - CryConditionVariable& operator = (const CryConditionVariable&); - -private: - int m_waitersCount; - CRY_CRITICAL_SECTION m_waitersCountLock; - void* m_sema; - void* m_waitersDone; - size_t m_wasBroadcast; -}; - -////////////////////////////////////////////////////////////////////////// -// Platform independet wrapper for a counting semaphore -class CrySemaphore -{ -public: - CrySemaphore(int nMaximumCount, int nInitialCount = 0); - ~CrySemaphore(); - void Acquire(); - void Release(); - -private: - void* m_Semaphore; -}; - -////////////////////////////////////////////////////////////////////////// -// Platform independet wrapper for a counting semaphore -// except that this version uses C-A-S only until a blocking call is needed -// -> No kernel call if there are object in the semaphore -class CryFastSemaphore -{ -public: - CryFastSemaphore(int nMaximumCount, int nInitialCount = 0); - ~CryFastSemaphore(); - void Acquire(); - void Release(); - -private: - CrySemaphore m_Semaphore; - volatile int32 m_nCounter; -}; From f85e8124a9ee10e2e337877d2f67e9033fa8eff4 Mon Sep 17 00:00:00 2001 From: kberg-amzn Date: Mon, 9 Aug 2021 16:17:23 -0700 Subject: [PATCH 11/70] Fixes and cleanup for recent correction changes Signed-off-by: kberg-amzn --- .../Serialization/StringifySerializer.cpp | 26 -------- .../Serialization/StringifySerializer.h | 12 +--- .../LocalPredictionPlayerInputComponent.h | 5 -- .../Multiplayer/Components/NetBindComponent.h | 4 ++ .../Components/NetworkTransformComponent.h | 2 + .../LocalPredictionPlayerInputComponent.cpp | 66 ++----------------- .../Source/Components/NetBindComponent.cpp | 10 +++ .../Components/NetworkTransformComponent.cpp | 14 ++++ 8 files changed, 36 insertions(+), 103 deletions(-) diff --git a/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.cpp b/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.cpp index df018cb6ce..4f31dd0f33 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.cpp @@ -10,19 +10,6 @@ namespace AzNetworking { - StringifySerializer::StringifySerializer(char delimeter, bool outputFieldNames, const AZStd::string& seperator) - : m_delimeter(delimeter) - , m_outputFieldNames(outputFieldNames) - , m_separator(seperator) - { - ; - } - - const AZStd::string& StringifySerializer::GetString() const - { - return m_string; - } - const StringifySerializer::ValueMap& StringifySerializer::GetValueMap() const { return m_valueMap; @@ -138,21 +125,8 @@ namespace AzNetworking bool StringifySerializer::ProcessData(const char* name, const T& value) { const AZStd::string keyString = m_prefix + name; - - if (!m_string.empty()) - { - // Only add delimeters after we have processed at least one element - m_string += m_delimeter; - } - - if (m_outputFieldNames) - { - m_string += keyString; - } - AZ::CVarFixedString valueString = AZ::ConsoleTypeHelpers::ValueToString(value); m_valueMap[keyString] = valueString.c_str(); - return true; } } diff --git a/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.h b/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.h index 379b5198c7..3ea0bfa412 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.h +++ b/Code/Framework/AzNetworking/AzNetworking/Serialization/StringifySerializer.h @@ -22,10 +22,7 @@ namespace AzNetworking using ValueMap = AZStd::map; - StringifySerializer(char delimeter = ' ', bool outputFieldNames = true, const AZStd::string& seperator = "="); - - //! After serializing objects, get the serialized values as a single string. - const AZStd::string& GetString() const; + StringifySerializer() = default; //! After serializing objects, get the serialized values as a map of key/value pairs. const ValueMap& GetValueMap() const; @@ -60,15 +57,8 @@ namespace AzNetworking template bool ProcessData(const char* name, const T& value); - private: - - char m_delimeter; - bool m_outputFieldNames = true; - ValueMap m_valueMap; - AZStd::string m_string; AZStd::string m_prefix; - AZStd::string m_separator; AZStd::deque m_prefixSizeStack; }; } diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/Components/LocalPredictionPlayerInputComponent.h b/Gems/Multiplayer/Code/Include/Multiplayer/Components/LocalPredictionPlayerInputComponent.h index 4e5d7f2d49..f26f043b85 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/Components/LocalPredictionPlayerInputComponent.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Components/LocalPredictionPlayerInputComponent.h @@ -14,8 +14,6 @@ namespace Multiplayer { - using CorrectionEvent = AZ::Event<>; - class LocalPredictionPlayerInputComponent : public LocalPredictionPlayerInputComponentBase { @@ -65,8 +63,6 @@ namespace Multiplayer ClientInputId GetLastInputId() const; HostFrameId GetInputFrameId(const NetworkInput& input) const; - void CorrectionEventAddHandle(CorrectionEvent::Handler& handler); - private: void OnMigrateStart(ClientInputId migratedInputId); @@ -86,7 +82,6 @@ namespace Multiplayer AZ::ScheduledEvent m_autonomousUpdateEvent; // Drives autonomous input collection AZ::ScheduledEvent m_updateBankedTimeEvent; // Drives authority bank time updates - CorrectionEvent m_correctionEvent; EntityMigrationStartEvent::Handler m_migrateStartHandler; EntityMigrationEndEvent::Handler m_migrateEndHandler; diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetBindComponent.h b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetBindComponent.h index c050495f1f..65bac09726 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetBindComponent.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetBindComponent.h @@ -36,6 +36,7 @@ namespace Multiplayer using EntityMigrationEndEvent = AZ::Event<>; using EntityServerMigrationEvent = AZ::Event; using EntityPreRenderEvent = AZ::Event; + using EntityCorrectionEvent = AZ::Event<>; //! @class NetBindComponent //! @brief Component that provides net-binding to a networked entity. @@ -118,6 +119,7 @@ namespace Multiplayer void NotifyMigrationEnd(); void NotifyServerMigration(HostId hostId, AzNetworking::ConnectionId connectionId); void NotifyPreRender(float deltaTime, float blendFactor); + void NotifyCorrection(); void AddEntityStopEventHandler(EntityStopEvent::Handler& eventHandler); void AddEntityDirtiedEventHandler(EntityDirtiedEvent::Handler& eventHandler); @@ -126,6 +128,7 @@ namespace Multiplayer void AddEntityMigrationEndEventHandler(EntityMigrationEndEvent::Handler& eventHandler); void AddEntityServerMigrationEventHandler(EntityServerMigrationEvent::Handler& eventHandler); void AddEntityPreRenderEventHandler(EntityPreRenderEvent::Handler& eventHandler); + void AddEntityCorrectionEventHandler(EntityCorrectionEvent::Handler& handler); bool SerializeEntityCorrection(AzNetworking::ISerializer& serializer); @@ -175,6 +178,7 @@ namespace Multiplayer EntityMigrationEndEvent m_entityMigrationEndEvent; EntityServerMigrationEvent m_entityServerMigrationEvent; EntityPreRenderEvent m_entityPreRenderEvent; + EntityCorrectionEvent m_entityCorrectionEvent; AZ::Event<> m_onRemove; RpcSendEvent::Handler m_handleLocalServerRpcMessageEventHandle; AZ::Event<>::Handler m_handleMarkedDirty; diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkTransformComponent.h b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkTransformComponent.h index 16aa8157aa..914aeaadd3 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkTransformComponent.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkTransformComponent.h @@ -30,6 +30,7 @@ namespace Multiplayer private: void OnPreRender(float deltaTime, float blendFactor); + void OnCorrection(); void OnRotationChangedEvent(const AZ::Quaternion& rotation); void OnTranslationChangedEvent(const AZ::Vector3& translation); @@ -47,6 +48,7 @@ namespace Multiplayer AZ::Event::Handler m_resetCountEventHandler; EntityPreRenderEvent::Handler m_entityPreRenderEventHandler; + EntityCorrectionEvent::Handler m_entityCorrectionEventHandler; Multiplayer::HostFrameId m_targetHostFrameId = HostFrameId(0); }; diff --git a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp index 4185b01798..5b6b93a3aa 100644 --- a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp @@ -32,21 +32,6 @@ namespace Multiplayer AZ_CVAR(AZ::TimeMs, sv_MinCorrectionTimeMs, AZ::TimeMs{ 100 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Minimum time to wait between sending out corrections in order to avoid flooding corrections on high-latency connections"); AZ_CVAR(AZ::TimeMs, sv_InputUpdateTimeMs, AZ::TimeMs{ 5 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Minimum time between component updates"); - // Debug helper functions - AZStd::string GetInputString(NetworkInput& input) - { - AzNetworking::StringifySerializer serializer(',', false); - input.Serialize(serializer); - return serializer.GetString(); - } - - AZStd::string GetCorrectionDataString(NetBindComponent* netBindComponent) - { - AzNetworking::StringifySerializer serializer(',', false); - netBindComponent->SerializeEntityCorrection(serializer); - return serializer.GetString(); - } - void PrintCorrectionDifferences(const AzNetworking::StringifySerializer& client, const AzNetworking::StringifySerializer& server) { const auto& clientMap = client.GetValueMap(); @@ -289,14 +274,7 @@ namespace Multiplayer ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), input.GetHostBlendFactor(), invokingConnection->GetConnectionId()); GetNetBindComponent()->ProcessInput(input, clientInputRateSec); - AZLOG - ( - NET_Prediction, - "Migrated InputId=%d - i=[%s] o=[%s]", - aznumeric_cast(input.GetClientInputId()), - GetInputString(input).c_str(), - GetCorrectionDataString(GetNetBindComponent()).c_str() - ); + AZLOG(NET_Prediction, "Migrated InputId=%d", aznumeric_cast(input.GetClientInputId())); // Don't bother checking for corrections here, the next regular input will trigger any corrections if necessary // Also don't bother with any cheat detection here, because the input array is limited in size and at most and can only be sent once @@ -329,7 +307,7 @@ namespace Multiplayer // Apply the correction AzNetworking::TrackChangedSerializer serializer(correction.GetBuffer(), correction.GetSize()); GetNetBindComponent()->SerializeEntityCorrection(serializer); - m_correctionEvent.Signal(); + GetNetBindComponent()->NotifyCorrection(); #ifndef AZ_RELEASE_BUILD if (cl_EnableDesyncDebugging) @@ -350,14 +328,6 @@ namespace Multiplayer } #endif - AZLOG - ( - NET_Prediction, - "Corrected InputId=%d - o=[%s]", - aznumeric_cast(m_lastCorrectionInputId), - GetCorrectionDataString(GetNetBindComponent()).c_str() - ); - const uint32_t inputHistorySize = m_inputHistory.Size(); const uint32_t historicalDelta = aznumeric_cast(m_clientInputId - inputId); // Do not replay the move we just corrected, that was already processed by the server @@ -372,14 +342,7 @@ namespace Multiplayer ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), input.GetHostBlendFactor(), invokingConnection->GetConnectionId()); GetNetBindComponent()->ReprocessInput(input, clientInputRateSec); - AZLOG - ( - NET_Prediction, - "Replayed InputId=%d - i=[%s] o=[%s]", - aznumeric_cast(input.GetClientInputId()), - GetInputString(input).c_str(), - GetCorrectionDataString(GetNetBindComponent()).c_str() - ); + AZLOG(NET_Prediction, "Replayed InputId=%d", aznumeric_cast(input.GetClientInputId())); } } @@ -402,11 +365,6 @@ namespace Multiplayer return (input.GetHostFrameId() == InvalidHostFrameId) ? m_serverMigrateFrameId : input.GetHostFrameId(); } - void LocalPredictionPlayerInputComponentController::CorrectionEventAddHandle(CorrectionEvent::Handler& handler) - { - handler.Connect(m_correctionEvent); - } - void LocalPredictionPlayerInputComponentController::OnMigrateStart(ClientInputId migratedInputId) { m_lastMigratedInputId = migratedInputId; @@ -480,14 +438,7 @@ namespace Multiplayer // Process the input for this frame GetNetBindComponent()->ProcessInput(input, inputRate); - AZLOG - ( - NET_Prediction, - "Processed InutId=%d - i=[%s] o=[%s]", - aznumeric_cast(m_clientInputId), - GetInputString(input).c_str(), - GetCorrectionDataString(GetNetBindComponent()).c_str() - ); + AZLOG(NET_Prediction, "Processed InputId=%d", aznumeric_cast(m_clientInputId)); // Generate a hash based on the current client predicted states AzNetworking::HashSerializer hashSerializer; @@ -553,14 +504,7 @@ namespace Multiplayer GetNetBindComponent()->ProcessInput(input, inputRate); } - AZLOG - ( - NET_Prediction, - "Forced InputId=%d - i=[%s] o=[%s]", - aznumeric_cast(input.GetClientInputId()), - GetInputString(input).c_str(), - GetCorrectionDataString(GetNetBindComponent()).c_str() - ); + AZLOG(NET_Prediction, "Forced InputId=%d", aznumeric_cast(input.GetClientInputId())); } // Decay our bank time window, in case the remote endpoint has suffered a more persistent shift in latency, this should cause the client to eventually recover diff --git a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp index cbbbadeffa..070655e768 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp @@ -408,6 +408,11 @@ namespace Multiplayer m_entityPreRenderEvent.Signal(deltaTime, blendFactor); } + void NetBindComponent::NotifyCorrection() + { + m_entityCorrectionEvent.Signal(); + } + void NetBindComponent::AddEntityStopEventHandler(EntityStopEvent::Handler& eventHandler) { eventHandler.Connect(m_entityStopEvent); @@ -443,6 +448,11 @@ namespace Multiplayer eventHandler.Connect(m_entityPreRenderEvent); } + void NetBindComponent::AddEntityCorrectionEventHandler(EntityCorrectionEvent::Handler& eventHandler) + { + eventHandler.Connect(m_entityCorrectionEvent); + } + bool NetBindComponent::SerializeEntityCorrection(AzNetworking::ISerializer& serializer) { m_predictableRecord.ResetConsumedBits(); diff --git a/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp index df4d7618fa..fa08794c4d 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetworkTransformComponent.cpp @@ -31,6 +31,7 @@ namespace Multiplayer , m_scaleEventHandler([this](float scale) { OnScaleChangedEvent(scale); }) , m_resetCountEventHandler([this](const uint8_t&) { OnResetCountChangedEvent(); }) , m_entityPreRenderEventHandler([this](float deltaTime, float blendFactor) { OnPreRender(deltaTime, blendFactor); }) + , m_entityCorrectionEventHandler([this]() { OnCorrection(); }) { ; } @@ -47,6 +48,7 @@ namespace Multiplayer ScaleAddEvent(m_scaleEventHandler); ResetCountAddEvent(m_resetCountEventHandler); GetNetBindComponent()->AddEntityPreRenderEventHandler(m_entityPreRenderEventHandler); + GetNetBindComponent()->AddEntityCorrectionEventHandler(m_entityCorrectionEventHandler); // When coming into relevance, reset all blending factors so we don't interpolate to our start position OnResetCountChangedEvent(); @@ -119,6 +121,18 @@ namespace Multiplayer } } + void NetworkTransformComponent::OnCorrection() + { + // Snap to latest + OnResetCountChangedEvent(); + + // Hard set the entities transform + if (!GetTransformComponent()->GetWorldTM().IsClose(m_targetTransform)) + { + GetTransformComponent()->SetWorldTM(m_targetTransform); + } + } + NetworkTransformComponentController::NetworkTransformComponentController(NetworkTransformComponent& parent) : NetworkTransformComponentControllerBase(parent) From 18709dad7a1afd2469d0cfbafa0ff10197cfb1b6 Mon Sep 17 00:00:00 2001 From: kberg-amzn Date: Mon, 9 Aug 2021 16:44:31 -0700 Subject: [PATCH 12/70] Removing imgui debug module from server target Signed-off-by: kberg-amzn --- Gems/Multiplayer/Code/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Multiplayer/Code/CMakeLists.txt b/Gems/Multiplayer/Code/CMakeLists.txt index e8b38c8799..96527fbfc4 100644 --- a/Gems/Multiplayer/Code/CMakeLists.txt +++ b/Gems/Multiplayer/Code/CMakeLists.txt @@ -79,7 +79,7 @@ ly_add_target( # The "Multiplayer" target is used by clients and servers, Debug is used only on clients. ly_create_alias(NAME Multiplayer.Clients NAMESPACE Gem TARGETS Gem::Multiplayer Gem::Multiplayer.Debug) -ly_create_alias(NAME Multiplayer.Servers NAMESPACE Gem TARGETS Gem::Multiplayer Gem::Multiplayer.Debug) +ly_create_alias(NAME Multiplayer.Servers NAMESPACE Gem TARGETS Gem::Multiplayer) if (PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( From 3bf4caf7d234ed86524e454b2d6c1e4b8462ac70 Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Mon, 9 Aug 2021 20:07:04 -0700 Subject: [PATCH 13/70] [redcode/crythread-2nd-pass] removed Cry*CriticalSection functions Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Code/Legacy/CryCommon/CryThreadImpl.h | 2 +- .../Legacy/CryCommon/CryThreadImpl_pthreads.h | 56 ------------------- Code/Legacy/CryCommon/MultiThread.h | 8 --- Code/Legacy/CryCommon/crycommon_files.cmake | 1 - Code/Legacy/CryCommon/platform_impl.cpp | 53 ------------------ 5 files changed, 1 insertion(+), 119 deletions(-) delete mode 100644 Code/Legacy/CryCommon/CryThreadImpl_pthreads.h diff --git a/Code/Legacy/CryCommon/CryThreadImpl.h b/Code/Legacy/CryCommon/CryThreadImpl.h index 0226b73716..4ff2cc6438 100644 --- a/Code/Legacy/CryCommon/CryThreadImpl.h +++ b/Code/Legacy/CryCommon/CryThreadImpl.h @@ -14,7 +14,7 @@ // Include architecture specific code. #if defined(LINUX) || defined(APPLE) -#include +// noting to include #define AZ_RESTRICTED_SECTION_IMPLEMENTED #elif defined(WIN32) || defined(WIN64) #include diff --git a/Code/Legacy/CryCommon/CryThreadImpl_pthreads.h b/Code/Legacy/CryCommon/CryThreadImpl_pthreads.h deleted file mode 100644 index 38838991a8..0000000000 --- a/Code/Legacy/CryCommon/CryThreadImpl_pthreads.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - - -#ifndef CRYINCLUDE_CRYCOMMON_CRYTHREADIMPL_PTHREADS_H -#define CRYINCLUDE_CRYCOMMON_CRYTHREADIMPL_PTHREADS_H -#pragma once - - -#include "CryThread_pthreads.h" - -/////////////////////////////////////////////////////////////////////////////// -// CryCriticalSection implementation -/////////////////////////////////////////////////////////////////////////////// -typedef CryLockT TCritSecType; - -void CryDeleteCriticalSection(void* cs) -{ - delete ((TCritSecType*)cs); -} - -void CryEnterCriticalSection(void* cs) -{ - ((TCritSecType*)cs)->Lock(); -} - -bool CryTryCriticalSection(void* cs) -{ - return false; -} - -void CryLeaveCriticalSection(void* cs) -{ - ((TCritSecType*)cs)->Unlock(); -} - -void CryCreateCriticalSectionInplace(void* pCS) -{ - new (pCS) TCritSecType; -} - -void CryDeleteCriticalSectionInplace(void*) -{ -} - -void* CryCreateCriticalSection() -{ - return (void*) new TCritSecType; -} - -#endif // CRYINCLUDE_CRYCOMMON_CRYTHREADIMPL_PTHREADS_H diff --git a/Code/Legacy/CryCommon/MultiThread.h b/Code/Legacy/CryCommon/MultiThread.h index 2b224c4743..c3aa892d14 100644 --- a/Code/Legacy/CryCommon/MultiThread.h +++ b/Code/Legacy/CryCommon/MultiThread.h @@ -48,14 +48,6 @@ LONG CryInterlockedCompareExchange(LONG volatile* dst, LONG exchange, LONG c void* CryInterlockedCompareExchangePointer(void* volatile* dst, void* exchange, void* comperand); void* CryInterlockedExchangePointer (void* volatile* dst, void* exchange); -void* CryCreateCriticalSection(); -void CryCreateCriticalSectionInplace(void*); -void CryDeleteCriticalSection(void* cs); -void CryDeleteCriticalSectionInplace(void* cs); -void CryEnterCriticalSection(void* cs); -bool CryTryCriticalSection(void* cs); -void CryLeaveCriticalSection(void* cs); - #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION MULTITHREAD_H_SECTION_DEFINE_CRYINTERLOCKEXCHANGE #include AZ_RESTRICTED_FILE(MultiThread_h) diff --git a/Code/Legacy/CryCommon/crycommon_files.cmake b/Code/Legacy/CryCommon/crycommon_files.cmake index b4dac2ec08..487d08b13c 100644 --- a/Code/Legacy/CryCommon/crycommon_files.cmake +++ b/Code/Legacy/CryCommon/crycommon_files.cmake @@ -162,7 +162,6 @@ set(FILES CryLibrary.h CryThread_pthreads.h CryThread_windows.h - CryThreadImpl_pthreads.h CryThreadImpl_windows.h CryWindows.h Linux32Specific.h diff --git a/Code/Legacy/CryCommon/platform_impl.cpp b/Code/Legacy/CryCommon/platform_impl.cpp index a677ba30b6..09d7493ae7 100644 --- a/Code/Legacy/CryCommon/platform_impl.cpp +++ b/Code/Legacy/CryCommon/platform_impl.cpp @@ -364,59 +364,6 @@ void CryInterlockedAdd(volatile size_t* pVal, ptrdiff_t iAdd) assert((iAdd == 0) || (iAdd < 0 && v < v - (size_t)iAdd) || (iAdd > 0 && v > v - (size_t)iAdd)); } -////////////////////////////////////////////////////////////////////////// -void* CryCreateCriticalSection() -{ - CRITICAL_SECTION* pCS = new CRITICAL_SECTION; - InitializeCriticalSection(pCS); - return pCS; -} - -void CryCreateCriticalSectionInplace(void* pCS) -{ - InitializeCriticalSection((CRITICAL_SECTION*)pCS); -} -////////////////////////////////////////////////////////////////////////// -void CryDeleteCriticalSection(void* cs) -{ - CRITICAL_SECTION* pCS = (CRITICAL_SECTION*)cs; - if (pCS->LockCount >= 0) - { - CryFatalError("Critical Section hanging lock"); - } - DeleteCriticalSection(pCS); - delete pCS; -} - -////////////////////////////////////////////////////////////////////////// -void CryDeleteCriticalSectionInplace(void* cs) -{ - CRITICAL_SECTION* pCS = (CRITICAL_SECTION*)cs; - if (pCS->LockCount >= 0) - { - CryFatalError("Critical Section hanging lock"); - } - DeleteCriticalSection(pCS); -} - -////////////////////////////////////////////////////////////////////////// -void CryEnterCriticalSection(void* cs) -{ - EnterCriticalSection((CRITICAL_SECTION*)cs); -} - -////////////////////////////////////////////////////////////////////////// -bool CryTryCriticalSection(void* cs) -{ - return TryEnterCriticalSection((CRITICAL_SECTION*)cs) != 0; -} - -////////////////////////////////////////////////////////////////////////// -void CryLeaveCriticalSection(void* cs) -{ - LeaveCriticalSection((CRITICAL_SECTION*)cs); -} - ////////////////////////////////////////////////////////////////////////// uint32 CryGetFileAttributes(const char* lpFileName) { From a70a106fd2e2f5b7b83739ab37355b06689afe33 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Tue, 10 Aug 2021 14:48:33 -0700 Subject: [PATCH 14/70] Test code to add merge detection on Settings Registry keys Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../AzCore/Component/ComponentApplication.cpp | 1 + .../AzCore/AzCore/Settings/SettingsRegistry.h | 44 ++++++++ .../AzCore/Settings/SettingsRegistryImpl.cpp | 49 +++++++++ .../AzCore/Settings/SettingsRegistryImpl.h | 9 ++ .../Settings/EditorSettingsOriginTracker.cpp | 103 ++++++++++++++++++ .../Settings/EditorSettingsOriginTracker.h | 39 +++++++ .../aztoolsframework_files.cmake | 2 + 7 files changed, 247 insertions(+) create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.cpp create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.h diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp index c68fce6f4d..7b1060a10f 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp @@ -728,6 +728,7 @@ namespace AZ DestroyReflectionManager(); static_cast(m_settingsRegistry.get())->ClearNotifiers(); + static_cast(m_settingsRegistry.get())->ClearMergeEvents(); // Uninit and unload any dynamic modules. m_moduleManager->UnloadModules(); diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h index 3bcf0ae89b..e27e4452ee 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h @@ -123,6 +123,36 @@ namespace AZ using NotifyEvent = AZ::Event; using NotifyEventHandler = typename NotifyEvent::Handler; + using PreMergeEventCallback = AZStd::function; + using PostMergeEventCallback = AZStd::function; + using PreMergeEvent = AZ::Event; + using PostMergeEvent = AZ::Event; + using PreMergeEventHandler = typename PreMergeEvent::Handler; + using PostMergeEventHandler = typename PostMergeEvent::Handler; + + struct ScopedMergeEvent + { + ScopedMergeEvent( + PreMergeEvent& preMergeEvent, PostMergeEvent& postMergeEvent, AZStd::string_view filePath, AZStd::string_view rootKey) + : m_preMergeEvent{ preMergeEvent } + , m_postMergeEvent{ postMergeEvent } + , m_filePath{ filePath } + , m_rootKey{ rootKey } + { + preMergeEvent.Signal(m_filePath, m_rootKey); + } + + ~ScopedMergeEvent() + { + m_postMergeEvent.Signal(m_filePath, m_rootKey); + } + + PreMergeEvent& m_preMergeEvent; + PostMergeEvent& m_postMergeEvent; + AZStd::string_view m_filePath; + AZStd::string_view m_rootKey; + }; + using VisitorCallback = AZStd::function; //! Base class for the visitor class during traversal over the Settings Registry. The type-agnostic function is always @@ -169,6 +199,20 @@ namespace AZ //! @callback The function to call when an entry gets a new/updated value. [[nodiscard]] virtual NotifyEventHandler RegisterNotifier(NotifyCallback&& callback) = 0; + //! Register a callback that will be called before an entry is merged. + //! @callback The function to call when an entry gets a new/updated value. + [[nodiscard]] virtual PreMergeEventHandler RegisterPreMergeEvent(const PreMergeEventCallback& callback) = 0; + //! Register a callback that will be called before an entry is merged. + //! @callback The function to call when an entry gets a new/updated value. + [[nodiscard]] virtual PreMergeEventHandler RegisterPreMergeEvent (PreMergeEventCallback&& callback) = 0; + + //! Register a callback that will be called after an entry is merged. + //! @callback The function to call when an entry gets a new/updated value. + [[nodiscard]] virtual PostMergeEventHandler RegisterPostMergeEvent(const PostMergeEventCallback& callback) = 0; + //! Register a callback that will be called after an entry is merged. + //! @callback The function to call when an entry gets a new/updated value. + [[nodiscard]] virtual PostMergeEventHandler RegisterPostMergeEvent (PostMergeEventCallback&& callback) = 0; + //! Gets the boolean value at the provided path. //! @param result The target to write the result to. //! @param path The path to the value. diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp index 0882e1b7f2..4a7b4183f3 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp @@ -229,6 +229,53 @@ namespace AZ m_notifiers.DisconnectAllHandlers(); } + auto SettingsRegistryImpl::RegisterPreMergeEvent(const PreMergeEventCallback& callback) -> PreMergeEventHandler + { + PreMergeEventHandler preMergeHandler{ callback }; + { + AZStd::scoped_lock lock(m_settingMutex); + preMergeHandler.Connect(m_preMergeEvent); + } + return preMergeHandler; + } + + auto SettingsRegistryImpl::RegisterPreMergeEvent(PreMergeEventCallback&& callback) -> PreMergeEventHandler + { + PreMergeEventHandler preMergeHandler{ AZStd::move(callback) }; + { + AZStd::scoped_lock lock(m_settingMutex); + preMergeHandler.Connect(m_preMergeEvent); + } + return preMergeHandler; + } + + auto SettingsRegistryImpl::RegisterPostMergeEvent(const PostMergeEventCallback& callback) -> PostMergeEventHandler + { + PostMergeEventHandler postMergeHandler{ callback }; + { + AZStd::scoped_lock lock(m_settingMutex); + postMergeHandler.Connect(m_postMergeEvent); + } + return postMergeHandler; + } + + auto SettingsRegistryImpl::RegisterPostMergeEvent(PostMergeEventCallback&& callback) -> PostMergeEventHandler + { + PostMergeEventHandler postMergeHandler{ AZStd::move(callback) }; + { + AZStd::scoped_lock lock(m_settingMutex); + postMergeHandler.Connect(m_postMergeEvent); + } + return postMergeHandler; + } + + void SettingsRegistryImpl::ClearMergeEvents() + { + AZStd::scoped_lock lock(m_settingMutex); + m_preMergeEvent.DisconnectAllHandlers(); + m_postMergeEvent.DisconnectAllHandlers(); + } + SettingsRegistryInterface::Type SettingsRegistryImpl::GetType(AZStd::string_view path) const { if (path.empty()) @@ -1115,6 +1162,8 @@ namespace AZ return false; } + ScopedMergeEvent(m_preMergeEvent, m_postMergeEvent, path, rootKey); + JsonSerializationResult::ResultCode mergeResult(JsonSerializationResult::Tasks::Merge); if (rootKey.empty()) { diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.h b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.h index 41a628cf22..babcafe701 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.h +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.h @@ -48,6 +48,12 @@ namespace AZ [[nodiscard]] NotifyEventHandler RegisterNotifier(NotifyCallback&& callback) override; void ClearNotifiers(); + [[nodiscard]] PreMergeEventHandler RegisterPreMergeEvent(const PreMergeEventCallback& callback) override; + [[nodiscard]] PreMergeEventHandler RegisterPreMergeEvent(PreMergeEventCallback&& callback) override; + [[nodiscard]] PostMergeEventHandler RegisterPostMergeEvent(const PostMergeEventCallback& callback) override; + [[nodiscard]] PostMergeEventHandler RegisterPostMergeEvent(PostMergeEventCallback&& callback) override; + void ClearMergeEvents(); + bool Get(bool& result, AZStd::string_view path) const override; bool Get(s64& result, AZStd::string_view path) const override; bool Get(u64& result, AZStd::string_view path) const override; @@ -103,6 +109,9 @@ namespace AZ mutable AZStd::recursive_mutex m_settingMutex; NotifyEvent m_notifiers; + PreMergeEvent m_preMergeEvent; + PostMergeEvent m_postMergeEvent; + rapidjson::Document m_settings; JsonSerializerSettings m_serializationSettings; JsonDeserializerSettings m_deserializationSettings; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.cpp new file mode 100644 index 0000000000..13a0610f5c --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.cpp @@ -0,0 +1,103 @@ +/* + * 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 +{ + EditorPreferencesSettingsOriginTracker::SettingsNotificationHandler::SettingsNotificationHandler( + AZ::SettingsRegistryInterface& registry) + : m_settingsRegistry(registry) + { + AZ::JsonApplyPatchSettings applyPatchSettings; + m_settingsRegistry.GetApplyPatchSettings(applyPatchSettings); + // Wrap any existing callbacks into the reporting callback, so that both this struct + // reporting callbacks and the existing callbacks can be invoked + m_prevReportingCallback = applyPatchSettings.m_reporting; + applyPatchSettings.m_reporting = [this]( + AZStd::string_view message, AZ::JsonSerializationResult::ResultCode result, + AZStd::string_view path) -> AZ::JsonSerializationResult::ResultCode + { + m_prevReportingCallback(message, result, path); + (*this)(message, result, path); + return result; + }; + m_settingsRegistry.SetApplyPatchSettings(applyPatchSettings); + } + + EditorPreferencesSettingsOriginTracker::SettingsNotificationHandler::~SettingsNotificationHandler() + { + // Restore previous reporting callback + AZ::JsonApplyPatchSettings applyPatchSettings; + m_settingsRegistry.GetApplyPatchSettings(applyPatchSettings); + applyPatchSettings.m_reporting = m_prevReportingCallback; + m_settingsRegistry.SetApplyPatchSettings(applyPatchSettings); + } + + // Use the Json Serialization Issue Callback system + // to determine when a merge option modifies a value + AZ::JsonSerializationResult::ResultCode EditorPreferencesSettingsOriginTracker::SettingsNotificationHandler::operator()( + AZStd::string_view /*message*/, AZ::JsonSerializationResult::ResultCode result, AZStd::string_view path) + { + using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString; + + AZ::IO::PathView preferencesRootKey{ "/Amazon/Preferences", AZ::IO::PosixPathSeparator }; + AZ::IO::PathView inputKey{ path, AZ::IO::PosixPathSeparator }; + + // Delegate to the Notifier Handler callable below + if (result.GetTask() == AZ::JsonSerializationResult::Tasks::Merge && + result.GetProcessing() == AZ::JsonSerializationResult::Processing::Completed && inputKey.IsRelativeTo(preferencesRootKey)) + { + if (auto type = m_settingsRegistry.GetType(path); type != AZ::SettingsRegistryInterface::Type::NoType) + { + operator()(path, type); + } + } + + return result; + } + + void EditorPreferencesSettingsOriginTracker::SettingsNotificationHandler::operator()( + AZStd::string_view path, AZ::SettingsRegistryInterface::Type /*type*/) + { + constexpr AZ::IO::PathView preferencesRootKey{ "/Amazon/Preferences", AZ::IO::PosixPathSeparator }; + AZ::IO::PathView inputKey{ path, AZ::IO::PosixPathSeparator }; + if (inputKey.IsRelativeTo(preferencesRootKey)) + { + // Do stuff with key + } + } + + EditorPreferencesSettingsOriginTracker::EditorPreferencesSettingsOriginTracker(AZ::SettingsRegistryInterface& registry) + : m_settingsRegistry(registry) + { + auto PreMergeEvent = [this](AZStd::string_view filePath, AZStd::string_view /*rootKey*/) + { + AZ::IO::FixedMaxPath editorPreferencesPath = AZ::Utils::GetProjectPath(); + editorPreferencesPath = editorPreferencesPath / "user" / "Registry" / "editorpreferences.setreg"; + + if (AZ::IO::PathView(filePath) == editorPreferencesPath) + { + m_notifyHandler = m_settingsRegistry.RegisterNotifier(SettingsNotificationHandler(m_settingsRegistry)); + } + }; + + auto PostMergeEvent = [this](AZStd::string_view /*filePath*/, AZStd::string_view /*rootKey*/) + { + // Clear the notification handler so that it goes out of scope + // and this tracker instance no handles settings updates + m_notifyHandler = {}; + }; + + m_preMergeEventHandler = m_settingsRegistry.RegisterPreMergeEvent(PreMergeEvent); + m_postMergeEventHandler = m_settingsRegistry.RegisterPostMergeEvent(PostMergeEvent); + } +} diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.h new file mode 100644 index 0000000000..63249a8ecd --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.h @@ -0,0 +1,39 @@ +/* + * 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 +{ + struct EditorPreferencesSettingsOriginTracker + { + explicit EditorPreferencesSettingsOriginTracker(AZ::SettingsRegistryInterface& registry); + + struct SettingsNotificationHandler + { + SettingsNotificationHandler(AZ::SettingsRegistryInterface& registry); + ~SettingsNotificationHandler(); + + AZ::JsonSerializationResult::ResultCode operator()( + AZStd::string_view message, AZ::JsonSerializationResult::ResultCode result, AZStd::string_view path); + void operator()(AZStd::string_view path, AZ::SettingsRegistryInterface::Type type); + + private: + AZ::SettingsRegistryInterface& m_settingsRegistry; + AZ::JsonSerializationResult::JsonIssueCallback m_prevReportingCallback; + }; + + private: + AZ::SettingsRegistryInterface& m_settingsRegistry; + AZ::SettingsRegistryInterface::PreMergeEventHandler m_preMergeEventHandler; + AZ::SettingsRegistryInterface::PostMergeEventHandler m_postMergeEventHandler; + AZ::SettingsRegistryInterface::NotifyEventHandler m_notifyHandler; + }; +} // namespace AZ diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index 53173f83af..6e7446d74d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -113,6 +113,8 @@ set(FILES Component/EditorLevelComponentAPIComponent.h Editor/EditorContextMenuBus.h Editor/EditorSettingsAPIBus.h + Editor/Settings/EditorSettingsOriginTracker.cpp + Editor/Settings/EditorSettingsOriginTracker.h Entity/EditorEntityStartStatus.h Entity/EditorEntityAPIBus.h Entity/EditorEntityContextComponent.cpp From 6f6b88ec2f785ff3ef8c2e56b6c4134df54d345a Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Tue, 10 Aug 2021 15:27:01 -0700 Subject: [PATCH 15/70] Rename EditorSettingsOriginTracker Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../Editor/Settings/EditorSettingsOriginTracker.cpp | 10 +++++----- .../Editor/Settings/EditorSettingsOriginTracker.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.cpp index 13a0610f5c..bdeb4e41b4 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.cpp @@ -13,7 +13,7 @@ namespace AzToolsFramework { - EditorPreferencesSettingsOriginTracker::SettingsNotificationHandler::SettingsNotificationHandler( + EditorSettingsOriginTracker::SettingsNotificationHandler::SettingsNotificationHandler( AZ::SettingsRegistryInterface& registry) : m_settingsRegistry(registry) { @@ -33,7 +33,7 @@ namespace AzToolsFramework m_settingsRegistry.SetApplyPatchSettings(applyPatchSettings); } - EditorPreferencesSettingsOriginTracker::SettingsNotificationHandler::~SettingsNotificationHandler() + EditorSettingsOriginTracker::SettingsNotificationHandler::~SettingsNotificationHandler() { // Restore previous reporting callback AZ::JsonApplyPatchSettings applyPatchSettings; @@ -44,7 +44,7 @@ namespace AzToolsFramework // Use the Json Serialization Issue Callback system // to determine when a merge option modifies a value - AZ::JsonSerializationResult::ResultCode EditorPreferencesSettingsOriginTracker::SettingsNotificationHandler::operator()( + AZ::JsonSerializationResult::ResultCode EditorSettingsOriginTracker::SettingsNotificationHandler::operator()( AZStd::string_view /*message*/, AZ::JsonSerializationResult::ResultCode result, AZStd::string_view path) { using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString; @@ -65,7 +65,7 @@ namespace AzToolsFramework return result; } - void EditorPreferencesSettingsOriginTracker::SettingsNotificationHandler::operator()( + void EditorSettingsOriginTracker::SettingsNotificationHandler::operator()( AZStd::string_view path, AZ::SettingsRegistryInterface::Type /*type*/) { constexpr AZ::IO::PathView preferencesRootKey{ "/Amazon/Preferences", AZ::IO::PosixPathSeparator }; @@ -76,7 +76,7 @@ namespace AzToolsFramework } } - EditorPreferencesSettingsOriginTracker::EditorPreferencesSettingsOriginTracker(AZ::SettingsRegistryInterface& registry) + EditorSettingsOriginTracker::EditorSettingsOriginTracker(AZ::SettingsRegistryInterface& registry) : m_settingsRegistry(registry) { auto PreMergeEvent = [this](AZStd::string_view filePath, AZStd::string_view /*rootKey*/) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.h index 63249a8ecd..3ef3f141a2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.h @@ -12,9 +12,9 @@ namespace AzToolsFramework { - struct EditorPreferencesSettingsOriginTracker + struct EditorSettingsOriginTracker { - explicit EditorPreferencesSettingsOriginTracker(AZ::SettingsRegistryInterface& registry); + explicit EditorSettingsOriginTracker(AZ::SettingsRegistryInterface& registry); struct SettingsNotificationHandler { From 88762b2b69992b6d28e37e94a163cf7e4691040c Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Tue, 10 Aug 2021 15:33:24 -0700 Subject: [PATCH 16/70] Add #pragma once to EditorSettingsOriginTracker to make it build :) Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../Editor/Settings/EditorSettingsOriginTracker.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.h index 3ef3f141a2..fbfdc1af25 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.h @@ -6,6 +6,8 @@ * */ +#pragma once + #include #include #include From f3fe8439a71a15fdfab6af58b384315efe8b9698 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Tue, 10 Aug 2021 17:29:27 -0700 Subject: [PATCH 17/70] Fix local variable declaration. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp index 4a7b4183f3..8b10013408 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp @@ -1162,7 +1162,7 @@ namespace AZ return false; } - ScopedMergeEvent(m_preMergeEvent, m_postMergeEvent, path, rootKey); + ScopedMergeEvent scopedMergeEvent(m_preMergeEvent, m_postMergeEvent, path, rootKey); JsonSerializationResult::ResultCode mergeResult(JsonSerializationResult::Tasks::Merge); if (rootKey.empty()) From 6db547302ea047479af2649db8f80da535412a8e Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Tue, 10 Aug 2021 17:32:39 -0700 Subject: [PATCH 18/70] Remove EditorSettingsOriginTracker (moved to prototype branch) Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../Settings/EditorSettingsOriginTracker.cpp | 103 ------------------ .../Settings/EditorSettingsOriginTracker.h | 41 ------- .../aztoolsframework_files.cmake | 2 - 3 files changed, 146 deletions(-) delete mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.cpp delete mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.h diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.cpp deleted file mode 100644 index bdeb4e41b4..0000000000 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include - -#include -#include - -namespace AzToolsFramework -{ - EditorSettingsOriginTracker::SettingsNotificationHandler::SettingsNotificationHandler( - AZ::SettingsRegistryInterface& registry) - : m_settingsRegistry(registry) - { - AZ::JsonApplyPatchSettings applyPatchSettings; - m_settingsRegistry.GetApplyPatchSettings(applyPatchSettings); - // Wrap any existing callbacks into the reporting callback, so that both this struct - // reporting callbacks and the existing callbacks can be invoked - m_prevReportingCallback = applyPatchSettings.m_reporting; - applyPatchSettings.m_reporting = [this]( - AZStd::string_view message, AZ::JsonSerializationResult::ResultCode result, - AZStd::string_view path) -> AZ::JsonSerializationResult::ResultCode - { - m_prevReportingCallback(message, result, path); - (*this)(message, result, path); - return result; - }; - m_settingsRegistry.SetApplyPatchSettings(applyPatchSettings); - } - - EditorSettingsOriginTracker::SettingsNotificationHandler::~SettingsNotificationHandler() - { - // Restore previous reporting callback - AZ::JsonApplyPatchSettings applyPatchSettings; - m_settingsRegistry.GetApplyPatchSettings(applyPatchSettings); - applyPatchSettings.m_reporting = m_prevReportingCallback; - m_settingsRegistry.SetApplyPatchSettings(applyPatchSettings); - } - - // Use the Json Serialization Issue Callback system - // to determine when a merge option modifies a value - AZ::JsonSerializationResult::ResultCode EditorSettingsOriginTracker::SettingsNotificationHandler::operator()( - AZStd::string_view /*message*/, AZ::JsonSerializationResult::ResultCode result, AZStd::string_view path) - { - using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString; - - AZ::IO::PathView preferencesRootKey{ "/Amazon/Preferences", AZ::IO::PosixPathSeparator }; - AZ::IO::PathView inputKey{ path, AZ::IO::PosixPathSeparator }; - - // Delegate to the Notifier Handler callable below - if (result.GetTask() == AZ::JsonSerializationResult::Tasks::Merge && - result.GetProcessing() == AZ::JsonSerializationResult::Processing::Completed && inputKey.IsRelativeTo(preferencesRootKey)) - { - if (auto type = m_settingsRegistry.GetType(path); type != AZ::SettingsRegistryInterface::Type::NoType) - { - operator()(path, type); - } - } - - return result; - } - - void EditorSettingsOriginTracker::SettingsNotificationHandler::operator()( - AZStd::string_view path, AZ::SettingsRegistryInterface::Type /*type*/) - { - constexpr AZ::IO::PathView preferencesRootKey{ "/Amazon/Preferences", AZ::IO::PosixPathSeparator }; - AZ::IO::PathView inputKey{ path, AZ::IO::PosixPathSeparator }; - if (inputKey.IsRelativeTo(preferencesRootKey)) - { - // Do stuff with key - } - } - - EditorSettingsOriginTracker::EditorSettingsOriginTracker(AZ::SettingsRegistryInterface& registry) - : m_settingsRegistry(registry) - { - auto PreMergeEvent = [this](AZStd::string_view filePath, AZStd::string_view /*rootKey*/) - { - AZ::IO::FixedMaxPath editorPreferencesPath = AZ::Utils::GetProjectPath(); - editorPreferencesPath = editorPreferencesPath / "user" / "Registry" / "editorpreferences.setreg"; - - if (AZ::IO::PathView(filePath) == editorPreferencesPath) - { - m_notifyHandler = m_settingsRegistry.RegisterNotifier(SettingsNotificationHandler(m_settingsRegistry)); - } - }; - - auto PostMergeEvent = [this](AZStd::string_view /*filePath*/, AZStd::string_view /*rootKey*/) - { - // Clear the notification handler so that it goes out of scope - // and this tracker instance no handles settings updates - m_notifyHandler = {}; - }; - - m_preMergeEventHandler = m_settingsRegistry.RegisterPreMergeEvent(PreMergeEvent); - m_postMergeEventHandler = m_settingsRegistry.RegisterPostMergeEvent(PostMergeEvent); - } -} diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.h deleted file mode 100644 index fbfdc1af25..0000000000 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Editor/Settings/EditorSettingsOriginTracker.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include -#include -#include - -namespace AzToolsFramework -{ - struct EditorSettingsOriginTracker - { - explicit EditorSettingsOriginTracker(AZ::SettingsRegistryInterface& registry); - - struct SettingsNotificationHandler - { - SettingsNotificationHandler(AZ::SettingsRegistryInterface& registry); - ~SettingsNotificationHandler(); - - AZ::JsonSerializationResult::ResultCode operator()( - AZStd::string_view message, AZ::JsonSerializationResult::ResultCode result, AZStd::string_view path); - void operator()(AZStd::string_view path, AZ::SettingsRegistryInterface::Type type); - - private: - AZ::SettingsRegistryInterface& m_settingsRegistry; - AZ::JsonSerializationResult::JsonIssueCallback m_prevReportingCallback; - }; - - private: - AZ::SettingsRegistryInterface& m_settingsRegistry; - AZ::SettingsRegistryInterface::PreMergeEventHandler m_preMergeEventHandler; - AZ::SettingsRegistryInterface::PostMergeEventHandler m_postMergeEventHandler; - AZ::SettingsRegistryInterface::NotifyEventHandler m_notifyHandler; - }; -} // namespace AZ diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index 6e7446d74d..53173f83af 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -113,8 +113,6 @@ set(FILES Component/EditorLevelComponentAPIComponent.h Editor/EditorContextMenuBus.h Editor/EditorSettingsAPIBus.h - Editor/Settings/EditorSettingsOriginTracker.cpp - Editor/Settings/EditorSettingsOriginTracker.h Entity/EditorEntityStartStatus.h Entity/EditorEntityAPIBus.h Entity/EditorEntityContextComponent.cpp From 737cf3093791efb073ad226cbe7703e840c958d5 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Tue, 10 Aug 2021 17:36:43 -0700 Subject: [PATCH 19/70] Fix documentation comments to be more accurate. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../AzCore/AzCore/Settings/SettingsRegistry.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h index e27e4452ee..106e232904 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h @@ -199,18 +199,18 @@ namespace AZ //! @callback The function to call when an entry gets a new/updated value. [[nodiscard]] virtual NotifyEventHandler RegisterNotifier(NotifyCallback&& callback) = 0; - //! Register a callback that will be called before an entry is merged. - //! @callback The function to call when an entry gets a new/updated value. + //! Register a function that will be called before a file is merged. + //! @callback The function to call before a file is merged. [[nodiscard]] virtual PreMergeEventHandler RegisterPreMergeEvent(const PreMergeEventCallback& callback) = 0; - //! Register a callback that will be called before an entry is merged. - //! @callback The function to call when an entry gets a new/updated value. + //! Register a function that will be called before a file is merged. + //! @callback The function to call before a file is merged. [[nodiscard]] virtual PreMergeEventHandler RegisterPreMergeEvent (PreMergeEventCallback&& callback) = 0; - //! Register a callback that will be called after an entry is merged. - //! @callback The function to call when an entry gets a new/updated value. + //! Register a function that will be called after a file is merged. + //! @callback The function to call after a file is merged. [[nodiscard]] virtual PostMergeEventHandler RegisterPostMergeEvent(const PostMergeEventCallback& callback) = 0; - //! Register a callback that will be called after an entry is merged. - //! @callback The function to call when an entry gets a new/updated value. + //! Register a function that will be called after a file is merged. + //! @callback The function to call after a file is merged. [[nodiscard]] virtual PostMergeEventHandler RegisterPostMergeEvent (PostMergeEventCallback&& callback) = 0; //! Gets the boolean value at the provided path. From f99f1f00f4de5696275db77cbbca5ee168891dab Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Tue, 10 Aug 2021 20:35:55 -0700 Subject: [PATCH 20/70] [redcode/crythread-2nd-pass] removed or replaced remaining CryMutex/CryLock usage with equivalent AZStd version Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Code/Editor/CryEdit.cpp | 18 +++++++++--------- Code/Editor/GameEngine.h | 4 ++-- Code/Editor/GameExporter.cpp | 2 +- Code/Editor/IEditorImpl.cpp | 6 +++--- Code/Editor/IEditorImpl.h | 2 +- .../PerforcePlugin/PerforceSourceControl.cpp | 8 ++++---- Code/Legacy/CryCommon/CryAssert_Linux.h | 4 ++-- Code/Legacy/CryCommon/CryAssert_Mac.h | 2 -- Code/Legacy/CryCommon/IMaterial.h | 2 -- .../Legacy/CryCommon/MultiThread_Containers.h | 6 +++--- .../Legacy/CrySystem/LocalizedStringManager.h | 4 ++-- Code/Legacy/CrySystem/Log.cpp | 19 ++++--------------- Code/Legacy/CrySystem/Log.h | 4 +--- .../CrySystem/SystemEventDispatcher.cpp | 12 ++++++------ Code/Legacy/CrySystem/SystemEventDispatcher.h | 2 +- 15 files changed, 39 insertions(+), 56 deletions(-) diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp index 5a5b17f799..fdde069e6f 100644 --- a/Code/Editor/CryEdit.cpp +++ b/Code/Editor/CryEdit.cpp @@ -891,7 +891,7 @@ CCrySingleDocTemplate::Confidence CCrySingleDocTemplate::MatchDocType(LPCTSTR lp ///////////////////////////////////////////////////////////////////////////// namespace { - CryMutex g_splashScreenStateLock; + AZStd::mutex g_splashScreenStateLock; enum ESplashScreenState { eSplashScreenState_Init, eSplashScreenState_Started, eSplashScreenState_Destroy @@ -922,7 +922,7 @@ QString FormatRichTextCopyrightNotice() ///////////////////////////////////////////////////////////////////////////// void CCryEditApp::ShowSplashScreen(CCryEditApp* app) { - g_splashScreenStateLock.Lock(); + g_splashScreenStateLock.lock(); CStartupLogoDialog* splashScreen = new CStartupLogoDialog(FormatVersion(app->m_pEditor->GetFileVersion()), FormatRichTextCopyrightNotice()); @@ -930,7 +930,7 @@ void CCryEditApp::ShowSplashScreen(CCryEditApp* app) g_splashScreen = splashScreen; g_splashScreenState = eSplashScreenState_Started; - g_splashScreenStateLock.Unlock(); + g_splashScreenStateLock.unlock(); splashScreen->show(); // Make sure the initial paint of the splash screen occurs so we dont get stuck with a blank window @@ -938,10 +938,10 @@ void CCryEditApp::ShowSplashScreen(CCryEditApp* app) QObject::connect(splashScreen, &QObject::destroyed, splashScreen, [=] { - g_splashScreenStateLock.Lock(); + g_splashScreenStateLock.lock(); g_pInitializeUIInfo = nullptr; g_splashScreen = nullptr; - g_splashScreenStateLock.Unlock(); + g_splashScreenStateLock.unlock(); }); } @@ -971,9 +971,9 @@ void CCryEditApp::CloseSplashScreen() if (CStartupLogoDialog::instance()) { delete CStartupLogoDialog::instance(); - g_splashScreenStateLock.Lock(); + g_splashScreenStateLock.lock(); g_splashScreenState = eSplashScreenState_Destroy; - g_splashScreenStateLock.Unlock(); + g_splashScreenStateLock.unlock(); } GetIEditor()->Notify(eNotify_OnSplashScreenDestroyed); @@ -982,12 +982,12 @@ void CCryEditApp::CloseSplashScreen() ///////////////////////////////////////////////////////////////////////////// void CCryEditApp::OutputStartupMessage(QString str) { - g_splashScreenStateLock.Lock(); + g_splashScreenStateLock.lock(); if (g_pInitializeUIInfo) { g_pInitializeUIInfo->SetInfoText(str.toUtf8().data()); } - g_splashScreenStateLock.Unlock(); + g_splashScreenStateLock.unlock(); } ////////////////////////////////////////////////////////////////////////// diff --git a/Code/Editor/GameEngine.h b/Code/Editor/GameEngine.h index 84df8bf002..4d183cc38e 100644 --- a/Code/Editor/GameEngine.h +++ b/Code/Editor/GameEngine.h @@ -116,11 +116,11 @@ public: //! mutex used by other threads to lock up the PAK modification, //! so only one thread can modify the PAK at once - static CryMutex& GetPakModifyMutex() + static AZStd::recursive_mutex& GetPakModifyMutex() { //! mutex used to halt copy process while the export to game //! or other pak operation is done in the main thread - static CryMutex s_pakModifyMutex; + static AZStd::recursive_mutex s_pakModifyMutex; return s_pakModifyMutex; } diff --git a/Code/Editor/GameExporter.cpp b/Code/Editor/GameExporter.cpp index 006eb9189c..d2a16ccc30 100644 --- a/Code/Editor/GameExporter.cpp +++ b/Code/Editor/GameExporter.cpp @@ -136,7 +136,7 @@ bool CGameExporter::Export(unsigned int flags, [[maybe_unused]] EEndian eExportE m_settings.SetHiQuality(); } - CryAutoLock autoLock(CGameEngine::GetPakModifyMutex()); + AZStd::lock_guard autoLock(CGameEngine::GetPakModifyMutex()); // Close this pak file. if (!CloseLevelPack(m_levelPak, true)) diff --git a/Code/Editor/IEditorImpl.cpp b/Code/Editor/IEditorImpl.cpp index c09c0a8e62..3c166fbca2 100644 --- a/Code/Editor/IEditorImpl.cpp +++ b/Code/Editor/IEditorImpl.cpp @@ -251,7 +251,7 @@ void CEditorImpl::Uninitialize() void CEditorImpl::UnloadPlugins() { - CryAutoLock lock(m_pluginMutex); + AZStd::lock_guard lock(m_pluginMutex); // Flush core buses. We're about to unload DLLs and need to ensure we don't have module-owned functions left behind. AZ::Data::AssetBus::ExecuteQueuedEvents(); @@ -272,7 +272,7 @@ void CEditorImpl::UnloadPlugins() void CEditorImpl::LoadPlugins() { - CryAutoLock lock(m_pluginMutex); + AZStd::lock_guard lock(m_pluginMutex); static const QString editor_plugins_folder("EditorPlugins"); @@ -1457,7 +1457,7 @@ void CEditorImpl::UnregisterNotifyListener(IEditorNotifyListener* listener) ISourceControl* CEditorImpl::GetSourceControl() { - CryAutoLock lock(m_pluginMutex); + AZStd::lock_guard lock(m_pluginMutex); if (m_pSourceControl) { diff --git a/Code/Editor/IEditorImpl.h b/Code/Editor/IEditorImpl.h index 65389a212e..275214bc57 100644 --- a/Code/Editor/IEditorImpl.h +++ b/Code/Editor/IEditorImpl.h @@ -401,7 +401,7 @@ protected: IImageUtil* m_pImageUtil; // Vladimir@conffx ILogFile* m_pLogFile; // Vladimir@conffx - CryMutex m_pluginMutex; // protect any pointers that come from plugins, such as the source control cached pointer. + AZStd::mutex m_pluginMutex; // protect any pointers that come from plugins, such as the source control cached pointer. static const char* m_crashLogFileName; }; diff --git a/Code/Editor/Plugins/PerforcePlugin/PerforceSourceControl.cpp b/Code/Editor/Plugins/PerforcePlugin/PerforceSourceControl.cpp index 581f9a576d..34514b8ef1 100644 --- a/Code/Editor/Plugins/PerforcePlugin/PerforceSourceControl.cpp +++ b/Code/Editor/Plugins/PerforcePlugin/PerforceSourceControl.cpp @@ -22,7 +22,7 @@ namespace { - CryCriticalSection g_cPerforceValues; + AZStd::mutex g_cPerforceValues; } //////////////////////////////////////////////////////////// @@ -30,9 +30,9 @@ ULONG STDMETHODCALLTYPE CPerforceSourceControl::Release() { if ((--m_ref) == 0) { - g_cPerforceValues.Lock(); + g_cPerforceValues.lock(); delete this; - g_cPerforceValues.Unlock(); + g_cPerforceValues.unlock(); return 0; } else @@ -56,7 +56,7 @@ void CPerforceSourceControl::ShowSettings() void CPerforceSourceControl::SetSourceControlState(SourceControlState state) { - CryAutoLock lock(g_cPerforceValues); + AZStd::lock_guard lock(g_cPerforceValues); switch (state) { diff --git a/Code/Legacy/CryCommon/CryAssert_Linux.h b/Code/Legacy/CryCommon/CryAssert_Linux.h index 3debe2bd5d..355194caba 100644 --- a/Code/Legacy/CryCommon/CryAssert_Linux.h +++ b/Code/Legacy/CryCommon/CryAssert_Linux.h @@ -72,7 +72,7 @@ bool CryAssert(const char* szCondition, const char* szFile, unsigned int line, b static const int max_len = 4096; static char gs_command_str[4096]; - static CryLockT lock; + static AZStd::recursive_mutex lock; gEnv->pSystem->OnAssert(szCondition, gs_szMessage, szFile, line); @@ -80,7 +80,7 @@ bool CryAssert(const char* szCondition, const char* szFile, unsigned int line, b if (!gEnv->bNoAssertDialog && !gEnv->bIgnoreAllAsserts) { - CryAutoLock< CryLockT > lk (lock); + AZStd::lock_guard lk (lock); snprintf(gs_command_str, max_len, "xterm -geometry 100x20 -n 'Assert Dialog [Linux Launcher]' -T 'Assert Dialog [Linux Launcher]' -e 'BinLinux/assert_term \"%s\" \"%s\" %d \"%s\"; echo \"$?\" > .assert_return'", szCondition, (file_len > 60) ? szFile + (file_len - 61) : szFile, line, gs_szMessage); int ret = system(gs_command_str); diff --git a/Code/Legacy/CryCommon/CryAssert_Mac.h b/Code/Legacy/CryCommon/CryAssert_Mac.h index ce65b352ab..f0a893630e 100644 --- a/Code/Legacy/CryCommon/CryAssert_Mac.h +++ b/Code/Legacy/CryCommon/CryAssert_Mac.h @@ -70,8 +70,6 @@ bool CryAssert(const char* szCondition, const char* szFile, unsigned int line, b static const int max_len = 4096; static char gs_command_str[4096]; - static CryLockT lock; - gEnv->pSystem->OnAssert(szCondition, gs_szMessage, szFile, line); size_t file_len = strlen(szFile); diff --git a/Code/Legacy/CryCommon/IMaterial.h b/Code/Legacy/CryCommon/IMaterial.h index 1faee0eef9..97a5100018 100644 --- a/Code/Legacy/CryCommon/IMaterial.h +++ b/Code/Legacy/CryCommon/IMaterial.h @@ -432,8 +432,6 @@ struct IMaterial virtual uint32 GetDccMaterialHash() const = 0; virtual void SetDccMaterialHash(uint32 hash) = 0; - virtual CryCriticalSection& GetSubMaterialResizeLock() = 0; - virtual void UpdateShaderItems() = 0; // diff --git a/Code/Legacy/CryCommon/MultiThread_Containers.h b/Code/Legacy/CryCommon/MultiThread_Containers.h index 23f7cd1e0c..8a60adfa6b 100644 --- a/Code/Legacy/CryCommon/MultiThread_Containers.h +++ b/Code/Legacy/CryCommon/MultiThread_Containers.h @@ -34,7 +34,7 @@ namespace CryMT public: typedef T value_type; typedef std::vector container_type; - typedef CryAutoCriticalSection AutoLock; + typedef AZStd::lock_guard AutoLock; ////////////////////////////////////////////////////////////////////////// // std::queue interface @@ -46,7 +46,7 @@ namespace CryMT // classic pop function of queue should not be used for thread safety, use try_pop instead //void pop() { AutoLock lock(m_cs); return v.erase(v.begin()); }; - CryCriticalSection& get_lock() const { return m_cs; } + AZStd::recursive_mutex& get_lock() const { return m_cs; } bool empty() const { AutoLock lock(m_cs); return v.empty(); } int size() const { AutoLock lock(m_cs); return v.size(); } @@ -92,7 +92,7 @@ namespace CryMT } private: container_type v; - mutable CryCriticalSection m_cs; + mutable AZStd::recursive_mutex m_cs; }; }; // namespace CryMT diff --git a/Code/Legacy/CrySystem/LocalizedStringManager.h b/Code/Legacy/CrySystem/LocalizedStringManager.h index 581a657c81..6916dee3c3 100644 --- a/Code/Legacy/CrySystem/LocalizedStringManager.h +++ b/Code/Legacy/CrySystem/LocalizedStringManager.h @@ -309,8 +309,8 @@ private: TLocalizationBitfield m_availableLocalizations; //Lock for - mutable CryCriticalSection m_cs; - typedef CryAutoCriticalSection AutoLock; + mutable AZStd::mutex m_cs; + typedef AZStd::lock_guard AutoLock; }; diff --git a/Code/Legacy/CrySystem/Log.cpp b/Code/Legacy/CrySystem/Log.cpp index 96bc29b58a..e7ba8f5ba7 100644 --- a/Code/Legacy/CrySystem/Log.cpp +++ b/Code/Legacy/CrySystem/Log.cpp @@ -32,17 +32,6 @@ #include #endif - -// Only accept logging from the main thread. -#ifdef WIN32 - -#define THREAD_SAFE_LOG -//#define THREAD_SAFE_LOG CryAutoCriticalSection scope_lock(m_logCriticalSection); - -#else -#define THREAD_SAFE_LOG -#endif //WIN32 - #define LOG_BACKUP_PATH "@log@/LogBackups" #if defined(IOS) @@ -822,13 +811,13 @@ void CLog::PushAssetScopeName(const char* sAssetType, const char* sName) SAssetScopeInfo as; as.sType = sAssetType; as.sName = sName; - CryAutoCriticalSection scope_lock(m_assetScopeQueueLock); + AZStd::lock_guard scope_lock(m_assetScopeQueueLock); m_assetScopeQueue.push_back(as); } void CLog::PopAssetScopeName() { - CryAutoCriticalSection scope_lock(m_assetScopeQueueLock); + AZStd::lock_guard scope_lock(m_assetScopeQueueLock); assert(!m_assetScopeQueue.empty()); if (!m_assetScopeQueue.empty()) { @@ -839,7 +828,7 @@ void CLog::PopAssetScopeName() ////////////////////////////////////////////////////////////////////////// const char* CLog::GetAssetScopeString() { - CryAutoCriticalSection scope_lock(m_assetScopeQueueLock); + AZStd::lock_guard scope_lock(m_assetScopeQueueLock); m_assetScopeString.clear(); for (size_t i = 0; i < m_assetScopeQueue.size(); i++) @@ -1470,7 +1459,7 @@ void CLog::Update() { if (!m_threadSafeMsgQueue.empty()) { - CryAutoCriticalSection lock(m_threadSafeMsgQueue.get_lock()); // Get the lock and hold onto it until we clear the entire queue (prevents other threads adding more things in while we clear it) + AZStd::lock_guard lock(m_threadSafeMsgQueue.get_lock()); // Get the lock and hold onto it until we clear the entire queue (prevents other threads adding more things in while we clear it) // Must be called from main thread SLogMsg msg; while (m_threadSafeMsgQueue.try_pop(msg)) diff --git a/Code/Legacy/CrySystem/Log.h b/Code/Legacy/CrySystem/Log.h index 5b1956b12f..d6b6dcea3e 100644 --- a/Code/Legacy/CrySystem/Log.h +++ b/Code/Legacy/CrySystem/Log.h @@ -168,7 +168,7 @@ private: // ------------------------------------------------------------------- }; std::vector m_assetScopeQueue; - CryCriticalSection m_assetScopeQueueLock; + AZStd::mutex m_assetScopeQueueLock; string m_assetScopeString; #endif @@ -176,8 +176,6 @@ private: // ------------------------------------------------------------------- IConsole* m_pConsole; // - CryCriticalSection m_logCriticalSection; - struct SLogHistoryItem { char str[MAX_WARNING_LENGTH]; diff --git a/Code/Legacy/CrySystem/SystemEventDispatcher.cpp b/Code/Legacy/CrySystem/SystemEventDispatcher.cpp index eb8113c501..525bf1a005 100644 --- a/Code/Legacy/CrySystem/SystemEventDispatcher.cpp +++ b/Code/Legacy/CrySystem/SystemEventDispatcher.cpp @@ -17,17 +17,17 @@ CSystemEventDispatcher::CSystemEventDispatcher() bool CSystemEventDispatcher::RegisterListener(ISystemEventListener* pListener) { - m_listenerRegistrationLock.Lock(); + m_listenerRegistrationLock.lock(); bool ret = m_listeners.Add(pListener); - m_listenerRegistrationLock.Unlock(); + m_listenerRegistrationLock.unlock(); return ret; } bool CSystemEventDispatcher::RemoveListener(ISystemEventListener* pListener) { - m_listenerRegistrationLock.Lock(); + m_listenerRegistrationLock.lock(); m_listeners.Remove(pListener); - m_listenerRegistrationLock.Unlock(); + m_listenerRegistrationLock.unlock(); return true; } @@ -35,12 +35,12 @@ bool CSystemEventDispatcher::RemoveListener(ISystemEventListener* pListener) ////////////////////////////////////////////////////////////////////////// void CSystemEventDispatcher::OnSystemEventAnyThread(ESystemEvent event, UINT_PTR wparam, UINT_PTR lparam) { - m_listenerRegistrationLock.Lock(); + m_listenerRegistrationLock.lock(); for (TSystemEventListeners::Notifier notifier(m_listeners); notifier.IsValid(); notifier.Next()) { notifier->OnSystemEventAnyThread(event, wparam, lparam); } - m_listenerRegistrationLock.Unlock(); + m_listenerRegistrationLock.unlock(); } diff --git a/Code/Legacy/CrySystem/SystemEventDispatcher.h b/Code/Legacy/CrySystem/SystemEventDispatcher.h index 37ce170abd..a5d33b2542 100644 --- a/Code/Legacy/CrySystem/SystemEventDispatcher.h +++ b/Code/Legacy/CrySystem/SystemEventDispatcher.h @@ -46,7 +46,7 @@ private: typedef CryMT::queue TSystemEventQueue; TSystemEventQueue m_systemEventQueue; - CryCriticalSection m_listenerRegistrationLock; + AZStd::recursive_mutex m_listenerRegistrationLock; }; #endif // CRYINCLUDE_CRYSYSTEM_SYSTEMEVENTDISPATCHER_H From 6f2b7baae8032203e5466384c255e1e3ea5bbda3 Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Tue, 10 Aug 2021 21:27:22 -0700 Subject: [PATCH 21/70] [redcode/crythread-2nd-pass] removed CryThread*.h files Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Code/Editor/Include/IObjectManager.h | 1 + Code/Editor/Objects/ObjectLoader.h | 2 + Code/Editor/QtUtil.h | 1 + Code/Editor/Util/FileUtil.h | 1 - Code/Editor/Util/Variable.h | 2 + Code/Legacy/CryCommon/CryThread.h | 110 ---------- Code/Legacy/CryCommon/CryThreadImpl.h | 29 --- Code/Legacy/CryCommon/CryThreadImpl_windows.h | 78 ------- Code/Legacy/CryCommon/CryThread_pthreads.h | 199 ------------------ Code/Legacy/CryCommon/CryThread_windows.h | 95 --------- Code/Legacy/CryCommon/Synchronization.h | 1 - Code/Legacy/CryCommon/crycommon_files.cmake | 5 - Code/Legacy/CryCommon/platform.h | 1 - Code/Legacy/CryCommon/platform_impl.cpp | 4 - Code/Legacy/CrySystem/Log.h | 1 - Code/Legacy/CrySystem/SystemEventDispatcher.h | 1 + 16 files changed, 7 insertions(+), 524 deletions(-) delete mode 100644 Code/Legacy/CryCommon/CryThread.h delete mode 100644 Code/Legacy/CryCommon/CryThreadImpl.h delete mode 100644 Code/Legacy/CryCommon/CryThreadImpl_windows.h delete mode 100644 Code/Legacy/CryCommon/CryThread_pthreads.h delete mode 100644 Code/Legacy/CryCommon/CryThread_windows.h diff --git a/Code/Editor/Include/IObjectManager.h b/Code/Editor/Include/IObjectManager.h index ce9d69681b..efc1955a56 100644 --- a/Code/Editor/Include/IObjectManager.h +++ b/Code/Editor/Include/IObjectManager.h @@ -14,6 +14,7 @@ #include #include #include +#include // forward declarations. class CEntityObject; diff --git a/Code/Editor/Objects/ObjectLoader.h b/Code/Editor/Objects/ObjectLoader.h index ccfaeb78f0..fc526970dd 100644 --- a/Code/Editor/Objects/ObjectLoader.h +++ b/Code/Editor/Objects/ObjectLoader.h @@ -15,6 +15,8 @@ #include "Util/GuidUtil.h" #include "ErrorReport.h" +#include + class CPakFile; class CErrorRecord; struct IObjectManager; diff --git a/Code/Editor/QtUtil.h b/Code/Editor/QtUtil.h index bb1f8ba427..69fe03baa1 100644 --- a/Code/Editor/QtUtil.h +++ b/Code/Editor/QtUtil.h @@ -12,6 +12,7 @@ #include #include #include "UnicodeFunctions.h" +#include #include #include diff --git a/Code/Editor/Util/FileUtil.h b/Code/Editor/Util/FileUtil.h index 3be66d6e96..6b2800dd27 100644 --- a/Code/Editor/Util/FileUtil.h +++ b/Code/Editor/Util/FileUtil.h @@ -9,7 +9,6 @@ #pragma once -#include "CryThread.h" #include "StringUtils.h" #include "../Include/SandboxAPI.h" #include diff --git a/Code/Editor/Util/Variable.h b/Code/Editor/Util/Variable.h index 83afee0924..ecd54e42ae 100644 --- a/Code/Editor/Util/Variable.h +++ b/Code/Editor/Util/Variable.h @@ -22,6 +22,8 @@ AZ_PUSH_DISABLE_WARNING(4458, "-Wunknown-warning-option") AZ_POP_DISABLE_WARNING #include +#include + inline const char* to_c_str(const char* str) { return str; } #define MAX_VAR_STRING_LENGTH 4096 diff --git a/Code/Legacy/CryCommon/CryThread.h b/Code/Legacy/CryCommon/CryThread.h deleted file mode 100644 index fcd7be16ba..0000000000 --- a/Code/Legacy/CryCommon/CryThread.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - - -// Description : Public include file for the multi-threading API. - - -#pragma once - - -// Include basic multithread primitives. -#include "MultiThread.h" -#include "BitFiddling.h" -#include -////////////////////////////////////////////////////////////////////////// -// Lock types: -// -// CRYLOCK_FAST -// A fast potentially (non-recursive) mutex. -// CRYLOCK_RECURSIVE -// A recursive mutex. -////////////////////////////////////////////////////////////////////////// -enum CryLockType -{ - CRYLOCK_FAST = 1, - CRYLOCK_RECURSIVE = 2, -}; - -#define CRYLOCK_HAVE_FASTLOCK 1 - -///////////////////////////////////////////////////////////////////////////// -// -// Primitive locks and conditions. -// -// Primitive locks are represented by instance of class CryLockT -// -// -template -class CryLockT -{ - /* Unsupported lock type. */ -}; - -////////////////////////////////////////////////////////////////////////// -// Typedefs. -////////////////////////////////////////////////////////////////////////// -typedef CryLockT CryCriticalSection; -typedef CryLockT CryCriticalSectionNonRecursive; -////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////// -// -// CryAutoCriticalSection implements a helper class to automatically -// lock critical section in constructor and release on destructor. -// -////////////////////////////////////////////////////////////////////////// -template -class CryAutoLock -{ -private: - LockClass* m_pLock; - - CryAutoLock(); - CryAutoLock(const CryAutoLock&); - CryAutoLock& operator = (const CryAutoLock&); - -public: - CryAutoLock(LockClass& Lock) - : m_pLock(&Lock) { m_pLock->Lock(); } - CryAutoLock(const LockClass& Lock) - : m_pLock(const_cast(&Lock)) { m_pLock->Lock(); } - ~CryAutoLock() { m_pLock->Unlock(); } -}; - -////////////////////////////////////////////////////////////////////////// -// -// Auto critical section is the most commonly used type of auto lock. -// -////////////////////////////////////////////////////////////////////////// -typedef CryAutoLock CryAutoCriticalSection; - -/////////////////////////////////////////////////////////////////////////////// -// Include architecture specific code. -#if AZ_LEGACY_CRYCOMMON_TRAIT_USE_PTHREADS -#include -#define AZ_RESTRICTED_SECTION_IMPLEMENTED -#elif defined(WIN32) || defined(WIN64) -#include -#define AZ_RESTRICTED_SECTION_IMPLEMENTED -#elif defined(AZ_RESTRICTED_PLATFORM) - #include AZ_RESTRICTED_FILE(CryThread_h) -#endif -#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) -#undef AZ_RESTRICTED_SECTION_IMPLEMENTED -#else -// Put other platform specific includes here! -#endif - -#if !defined _CRYTHREAD_CONDLOCK_GLITCH -typedef CryLockT CryMutex; -#endif // !_CRYTHREAD_CONDLOCK_GLITCH - -// Include all multithreading containers. -#include "MultiThread_Containers.h" diff --git a/Code/Legacy/CryCommon/CryThreadImpl.h b/Code/Legacy/CryCommon/CryThreadImpl.h deleted file mode 100644 index 4ff2cc6438..0000000000 --- a/Code/Legacy/CryCommon/CryThreadImpl.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - - -#pragma once - - -#include - -// Include architecture specific code. -#if defined(LINUX) || defined(APPLE) -// noting to include -#define AZ_RESTRICTED_SECTION_IMPLEMENTED -#elif defined(WIN32) || defined(WIN64) -#include -#define AZ_RESTRICTED_SECTION_IMPLEMENTED -#elif defined(AZ_RESTRICTED_PLATFORM) - #include AZ_RESTRICTED_FILE(CryThreadImpl_h) -#endif -#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) -#undef AZ_RESTRICTED_SECTION_IMPLEMENTED -#else -// Put other platform specific includes here! -#endif diff --git a/Code/Legacy/CryCommon/CryThreadImpl_windows.h b/Code/Legacy/CryCommon/CryThreadImpl_windows.h deleted file mode 100644 index 9157bde9bc..0000000000 --- a/Code/Legacy/CryCommon/CryThreadImpl_windows.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - - -#pragma once - -#include -#include // for CreateSemaphore - - -////////////////////////////////////////////////////////////////////////// -// CryLock_WinMutex -////////////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////////// -CryLock_WinMutex::CryLock_WinMutex() - : m_hdl(CreateMutex(NULL, FALSE, NULL)) {} -CryLock_WinMutex::~CryLock_WinMutex() -{ - CloseHandle(m_hdl); -} - -////////////////////////////////////////////////////////////////////////// -void CryLock_WinMutex::Lock() -{ - WaitForSingleObject(m_hdl, INFINITE); -} - -////////////////////////////////////////////////////////////////////////// -void CryLock_WinMutex::Unlock() -{ - ReleaseMutex(m_hdl); -} - -////////////////////////////////////////////////////////////////////////// -bool CryLock_WinMutex::TryLock() -{ - return WaitForSingleObject(m_hdl, 0) != WAIT_TIMEOUT; -} - -////////////////////////////////////////////////////////////////////////// -// CryLock_CritSection -////////////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////////// -CryLock_CritSection::CryLock_CritSection() -{ - InitializeCriticalSection((CRITICAL_SECTION*)&m_cs); -} - -////////////////////////////////////////////////////////////////////////// -CryLock_CritSection::~CryLock_CritSection() -{ - DeleteCriticalSection((CRITICAL_SECTION*)&m_cs); -} - -////////////////////////////////////////////////////////////////////////// -void CryLock_CritSection::Lock() -{ - EnterCriticalSection((CRITICAL_SECTION*)&m_cs); -} - -////////////////////////////////////////////////////////////////////////// -void CryLock_CritSection::Unlock() -{ - LeaveCriticalSection((CRITICAL_SECTION*)&m_cs); -} - -////////////////////////////////////////////////////////////////////////// -bool CryLock_CritSection::TryLock() -{ - return TryEnterCriticalSection((CRITICAL_SECTION*)&m_cs) != FALSE; -} diff --git a/Code/Legacy/CryCommon/CryThread_pthreads.h b/Code/Legacy/CryCommon/CryThread_pthreads.h deleted file mode 100644 index 9e04784f3f..0000000000 --- a/Code/Legacy/CryCommon/CryThread_pthreads.h +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - - -#pragma once - -#include - - -#include -#include -#include -#include -#include - -#include -#include -#include - -// Section dictionary -#if defined(AZ_RESTRICTED_PLATFORM) -#define CRYTHREAD_PTHREADS_H_SECTION_REGISTER_THREAD 1 -#define CRYTHREAD_PTHREADS_H_SECTION_TRAITS 2 -#define CRYTHREAD_PTHREADS_H_SECTION_PTHREADCOND 3 -#define CRYTHREAD_PTHREADS_H_SECTION_SEMAPHORE_CONSTRUCT 4 -#define CRYTHREAD_PTHREADS_H_SECTION_SEMAPHORE_DESTROY 5 -#define CRYTHREAD_PTHREADS_H_SECTION_SEMAPHORE_ACQUIRE 6 -#define CRYTHREAD_PTHREADS_H_SECTION_SEMAPHORE_RELEASE 7 -#define CRYTHREAD_PTHREADS_H_SECTION_TRY_RLOCK 8 -#define CRYTHREAD_PTHREADS_H_SECTION_TRY_WLOCK 9 -#define CRYTHREAD_PTHREADS_H_SECTION_START_RUNNABLE 10 -#define CRYTHREAD_PTHREADS_H_SECTION_START_CPUMASK 11 -#define CRYTHREAD_PTHREADS_H_SECTION_START_CPUMASK_POSTCREATE 12 -#define CRYTHREAD_PTHREADS_H_SECTION_SETCPUMASK 13 -#define CRYTHREAD_PTHREADS_H_SECTION_START_RUNNABLE_CPUMASK_POSTCREATE 14 -#endif - -#if defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION CRYTHREAD_PTHREADS_H_SECTION_REGISTER_THREAD - #include AZ_RESTRICTED_FILE(CryThread_pthreads_h) -#endif -#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) - #undef AZ_RESTRICTED_SECTION_IMPLEMENTED -#endif - -#if defined(APPLE) || defined(ANDROID) -// PTHREAD_MUTEX_FAST_NP is only defined by Pthreads-w32, thus not on MAC - #define PTHREAD_MUTEX_FAST_NP PTHREAD_MUTEX_NORMAL -#endif - -#if !defined _CRYTHREAD_HAVE_LOCK -template -class _PthreadLockBase; - -template -class _PthreadLockAttr -{ - friend class _PthreadLockBase; - -protected: - _PthreadLockAttr() - { - pthread_mutexattr_init(&m_Attr); - pthread_mutexattr_settype(&m_Attr, PthreadMutexType); - } - ~_PthreadLockAttr() - { - pthread_mutexattr_destroy(&m_Attr); - } - pthread_mutexattr_t m_Attr; -}; - -template -class _PthreadLockBase -{ -protected: - static pthread_mutexattr_t& GetAttr() - { - static _PthreadLockAttr m_Attr; - return m_Attr.m_Attr; - } -}; - -template -class _PthreadLock - : public _PthreadLockBase -{ - //#if defined(_DEBUG) -public: - //#endif - pthread_mutex_t m_Lock; - -public: - _PthreadLock() - : LockCount(0) - { - pthread_mutex_init( - &m_Lock, - &_PthreadLockBase::GetAttr()); - } - ~_PthreadLock() { pthread_mutex_destroy(&m_Lock); } - - void Lock() { pthread_mutex_lock(&m_Lock); CryInterlockedIncrement(&LockCount); } - - bool TryLock() - { - const int rc = pthread_mutex_trylock(&m_Lock); - if (0 == rc) - { - CryInterlockedIncrement(&LockCount); - return true; - } - return false; - } - - void Unlock() { CryInterlockedDecrement(&LockCount); pthread_mutex_unlock(&m_Lock); } - - // Get the POSIX pthread_mutex_t. - // Warning: - // This method will not be available in the Win32 port of CryThread. - pthread_mutex_t& Get_pthread_mutex_t() { return m_Lock; } - - bool IsLocked() - { -#if defined(LINUX) || defined(APPLE) - // implementation taken from CrysisWars - return LockCount > 0; -#else - return true; -#endif - } - -private: - volatile int LockCount; -}; - -#if defined CRYLOCK_HAVE_FASTLOCK - #if defined(_DEBUG) && defined(PTHREAD_MUTEX_ERRORCHECK_NP) -template<> -class CryLockT - : public _PthreadLock, PTHREAD_MUTEX_ERRORCHECK_NP> - #else -template<> -class CryLockT - : public _PthreadLock, PTHREAD_MUTEX_FAST_NP> - #endif -{ - CryLockT(const CryLockT&); - void operator = (const CryLockT&); - -public: - CryLockT() { } -}; -#endif // CRYLOCK_HAVE_FASTLOCK - -template<> -class CryLockT - : public _PthreadLock, PTHREAD_MUTEX_RECURSIVE> -{ - CryLockT(const CryLockT&); - void operator = (const CryLockT&); - -public: - CryLockT() { } -}; - -#if defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION CRYTHREAD_PTHREADS_H_SECTION_TRAITS - #include AZ_RESTRICTED_FILE(CryThread_pthreads_h) -#else -#if !defined(LINUX) && !defined(APPLE) -#define CRYTHREAD_PTHREADS_H_TRAIT_DEFINE_CRYMUTEX 1 -#endif -#endif - -#if CRYTHREAD_PTHREADS_H_TRAIT_DEFINE_CRYMUTEX -#if defined CRYLOCK_HAVE_FASTLOCK -class CryMutex - : public CryLockT -{ -}; -#else -class CryMutex - : public CryLockT -{ -}; -#endif -#endif // CRYTHREAD_PTHREADS_TRAIT_DEFINE_CRYMUTEX - -#define _CRYTHREAD_HAVE_LOCK 1 - -#endif // !defined _CRYTHREAD_HAVE_LOCK - -#include "MemoryAccess.h" diff --git a/Code/Legacy/CryCommon/CryThread_windows.h b/Code/Legacy/CryCommon/CryThread_windows.h deleted file mode 100644 index 5f83aa48e0..0000000000 --- a/Code/Legacy/CryCommon/CryThread_windows.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - - -#pragma once - -#include - -#if defined(AZ_RESTRICTED_PLATFORM) -#undef AZ_RESTRICTED_SECTION -#define CRYTHREAD_WINDOWS_H_SECTION_1 1 -#define CRYTHREAD_WINDOWS_H_SECTION_2 2 -#endif - -////////////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////////// -// from winnt.h -struct CRY_CRITICAL_SECTION -{ - void* DebugInfo; - long LockCount; - long RecursionCount; - threadID OwningThread; - void* LockSemaphore; - unsigned long* SpinCount; // force size on 64-bit systems when packed -}; - -////////////////////////////////////////////////////////////////////////// - -// kernel mutex - don't use... use CryMutex instead -class CryLock_WinMutex -{ -public: - CryLock_WinMutex(); - ~CryLock_WinMutex(); - - void Lock(); - void Unlock(); - bool TryLock(); - - void* _get_win32_handle() { return m_hdl; } - -private: - CryLock_WinMutex(const CryLock_WinMutex&); - CryLock_WinMutex& operator = (const CryLock_WinMutex&); - -private: - void* m_hdl; -}; - -// critical section... don't use... use CryCriticalSection instead -class CryLock_CritSection -{ -public: - CryLock_CritSection(); - ~CryLock_CritSection(); - - void Lock(); - void Unlock(); - bool TryLock(); - - bool IsLocked() - { - return m_cs.RecursionCount > 0 && m_cs.OwningThread == CryGetCurrentThreadId(); - } - -private: - CryLock_CritSection(const CryLock_CritSection&); - CryLock_CritSection& operator = (const CryLock_CritSection&); - -private: - CRY_CRITICAL_SECTION m_cs; -}; - -template <> -class CryLockT - : public CryLock_CritSection -{ -}; -template <> -class CryLockT - : public CryLock_CritSection -{ -}; -class CryMutex - : public CryLock_WinMutex -{ -}; -#define _CRYTHREAD_CONDLOCK_GLITCH 1 diff --git a/Code/Legacy/CryCommon/Synchronization.h b/Code/Legacy/CryCommon/Synchronization.h index 4caa466cb8..3bac215998 100644 --- a/Code/Legacy/CryCommon/Synchronization.h +++ b/Code/Legacy/CryCommon/Synchronization.h @@ -22,7 +22,6 @@ //--------------------------------------------------------------------------- #include "MultiThread.h" -#include "CryThread.h" namespace stl { diff --git a/Code/Legacy/CryCommon/crycommon_files.cmake b/Code/Legacy/CryCommon/crycommon_files.cmake index 487d08b13c..d9d4493632 100644 --- a/Code/Legacy/CryCommon/crycommon_files.cmake +++ b/Code/Legacy/CryCommon/crycommon_files.cmake @@ -89,8 +89,6 @@ set(FILES CrySizer.h CryString.h CrySystemBus.h - CryThread.h - CryThreadImpl.h CryTypeInfo.h CryVersion.h FrameProfiler.h @@ -160,9 +158,6 @@ set(FILES CryAssert_Mac.h CryLibrary.cpp CryLibrary.h - CryThread_pthreads.h - CryThread_windows.h - CryThreadImpl_windows.h CryWindows.h Linux32Specific.h Linux64Specific.h diff --git a/Code/Legacy/CryCommon/platform.h b/Code/Legacy/CryCommon/platform.h index 851da316e0..9f6e8b212d 100644 --- a/Code/Legacy/CryCommon/platform.h +++ b/Code/Legacy/CryCommon/platform.h @@ -732,7 +732,6 @@ typedef int socklen_t; // Include MultiThreading support. -#include "CryThread.h" #include "MultiThread.h" // In RELEASE disable printf and fprintf diff --git a/Code/Legacy/CryCommon/platform_impl.cpp b/Code/Legacy/CryCommon/platform_impl.cpp index 09d7493ae7..e16b18bc06 100644 --- a/Code/Legacy/CryCommon/platform_impl.cpp +++ b/Code/Legacy/CryCommon/platform_impl.cpp @@ -38,10 +38,6 @@ struct SSystemGlobalEnvironment* gEnv = nullptr; #include AZ_RESTRICTED_FILE(platform_impl_h) #endif -////////////////////////////////////////////////////////////////////////// -// If not in static library. -#include - #if defined(WIN32) || defined(WIN64) void CryPureCallHandler() { diff --git a/Code/Legacy/CrySystem/Log.h b/Code/Legacy/CrySystem/Log.h index d6b6dcea3e..447186e613 100644 --- a/Code/Legacy/CrySystem/Log.h +++ b/Code/Legacy/CrySystem/Log.h @@ -10,7 +10,6 @@ #pragma once #include -#include #include #include diff --git a/Code/Legacy/CrySystem/SystemEventDispatcher.h b/Code/Legacy/CrySystem/SystemEventDispatcher.h index a5d33b2542..550292add7 100644 --- a/Code/Legacy/CrySystem/SystemEventDispatcher.h +++ b/Code/Legacy/CrySystem/SystemEventDispatcher.h @@ -14,6 +14,7 @@ #include #include +#include class CSystemEventDispatcher : public ISystemEventDispatcher From adf7a34ef58196fac2863509d35077efb19a050e Mon Sep 17 00:00:00 2001 From: antonmic <56370189+antonmic@users.noreply.github.com> Date: Tue, 10 Aug 2021 23:07:23 -0700 Subject: [PATCH 22/70] Got PassBuilder shader dependency working and removed critical flag from shader builder Signed-off-by: antonmic <56370189+antonmic@users.noreply.github.com> --- .../Editor/ShaderVariantAssetBuilder.cpp | 2 +- .../AuxGeom/DynamicPrimitiveProcessor.cpp | 2 +- .../Source/AuxGeom/FixedShapeProcessor.cpp | 4 +- .../DiffuseProbeGridBlendDistancePass.cpp | 2 +- .../DiffuseProbeGridBlendIrradiancePass.cpp | 2 +- .../DiffuseProbeGridBorderUpdatePass.cpp | 2 +- .../DiffuseProbeGridClassificationPass.cpp | 2 +- .../DiffuseProbeGridFeatureProcessor.cpp | 2 +- .../DiffuseProbeGridRayTracingPass.cpp | 6 +- .../DiffuseProbeGridRelocationPass.cpp | 2 +- .../DiffuseProbeGridRenderPass.cpp | 2 +- .../Common/Code/Source/ImGui/ImGuiPass.cpp | 2 +- .../ReflectionProbeFeatureProcessor.cpp | 2 +- .../ReflectionScreenSpaceBlurPass.cpp | 4 +- .../Code/Include/Atom/RPI.Public/RPIUtils.h | 4 +- .../Source/RPI.Builders/Pass/PassBuilder.cpp | 127 +++++++----------- .../RPI.Public/Pass/AttachmentReadback.cpp | 2 +- .../RPI/Code/Source/RPI.Public/RPIUtils.cpp | 28 +++- Gems/LyShine/Code/Source/Draw2d.cpp | 2 +- Gems/LyShine/Code/Source/UiRenderer.cpp | 2 +- 20 files changed, 103 insertions(+), 98 deletions(-) diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp index ee02ae8452..1da4623774 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp @@ -321,7 +321,7 @@ namespace AZ AssetBuilderSDK::JobDescriptor jobDescriptor; jobDescriptor.m_priority = -5000; - jobDescriptor.m_critical = true; + jobDescriptor.m_critical = false; jobDescriptor.m_jobKey = ShaderVariantAssetBuilderJobKey; jobDescriptor.SetPlatformIdentifier(info.m_identifier.data()); diff --git a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/DynamicPrimitiveProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/DynamicPrimitiveProcessor.cpp index ea726dd914..3a7d50d2a9 100644 --- a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/DynamicPrimitiveProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/DynamicPrimitiveProcessor.cpp @@ -322,7 +322,7 @@ namespace AZ { const char* auxGeomWorldShaderFilePath = "Shaders/auxgeom/auxgeomworld.azshader"; - m_shader = RPI::LoadShader(auxGeomWorldShaderFilePath); + m_shader = RPI::LoadCriticalShader(auxGeomWorldShaderFilePath); if (!m_shader) { AZ_Error("DynamicPrimitiveProcessor", false, "Failed to get shader"); diff --git a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/FixedShapeProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/FixedShapeProcessor.cpp index 63feee115d..f2b3a93a53 100644 --- a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/FixedShapeProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/FixedShapeProcessor.cpp @@ -1385,9 +1385,9 @@ namespace AZ const char* litObjectShaderFilePath = "Shaders/auxgeom/auxgeomobjectlit.azshader"; // constant color shader - m_unlitShader = RPI::LoadShader(unlitObjectShaderFilePath); + m_unlitShader = RPI::LoadCriticalShader(unlitObjectShaderFilePath); // direction light shader - m_litShader = RPI::LoadShader(litObjectShaderFilePath); + m_litShader = RPI::LoadCriticalShader(litObjectShaderFilePath); if (m_unlitShader.get() == nullptr || m_litShader == nullptr) { diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp index 5fe472c7f8..a3927b802d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp @@ -38,7 +38,7 @@ namespace AZ // load shader // Note: the shader may not be available on all platforms AZStd::string shaderFilePath = "Shaders/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistance.azshader"; - m_shader = RPI::LoadShader(shaderFilePath); + m_shader = RPI::LoadCriticalShader(shaderFilePath); if (m_shader == nullptr) { return; diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp index c1b6653024..6ff8bdd867 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp @@ -38,7 +38,7 @@ namespace AZ // load shader // Note: the shader may not be available on all platforms AZStd::string shaderFilePath = "Shaders/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiance.azshader"; - m_shader = RPI::LoadShader(shaderFilePath); + m_shader = RPI::LoadCriticalShader(shaderFilePath); if (m_shader == nullptr) { return; diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.cpp index 0d47b3bd54..ddfe0f11b1 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.cpp @@ -51,7 +51,7 @@ namespace AZ { // load shader // Note: the shader may not be available on all platforms - shader = RPI::LoadShader(shaderFilePath); + shader = RPI::LoadCriticalShader(shaderFilePath); if (shader == nullptr) { return; diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp index bb7f87cc61..4c6b07d780 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp @@ -42,7 +42,7 @@ namespace AZ // load shader // Note: the shader may not be available on all platforms AZStd::string shaderFilePath = "Shaders/DiffuseGlobalIllumination/DiffuseProbeGridClassification.azshader"; - m_shader = RPI::LoadShader(shaderFilePath); + m_shader = RPI::LoadCriticalShader(shaderFilePath); if (m_shader == nullptr) { return; diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp index f4df4f126a..378e1923f7 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp @@ -74,7 +74,7 @@ namespace AZ // load shader // Note: the shader may not be available on all platforms - Data::Instance shader = RPI::LoadShader("Shaders/DiffuseGlobalIllumination/DiffuseProbeGridRender.azshader"); + Data::Instance shader = RPI::LoadCriticalShader("Shaders/DiffuseGlobalIllumination/DiffuseProbeGridRender.azshader"); if (shader) { m_probeGridRenderData.m_drawListTag = shader->GetDrawListTag(); diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.cpp index dd8985935f..958823ef91 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.cpp @@ -52,7 +52,7 @@ namespace AZ // load the ray tracing shader // Note: the shader may not be available on all platforms AZStd::string shaderFilePath = "Shaders/DiffuseGlobalIllumination/DiffuseProbeGridRayTracing.azshader"; - m_rayTracingShader = RPI::LoadShader(shaderFilePath); + m_rayTracingShader = RPI::LoadCriticalShader(shaderFilePath); if (m_rayTracingShader == nullptr) { return; @@ -64,7 +64,7 @@ namespace AZ // closest hit shader AZStd::string closestHitShaderFilePath = "Shaders/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingClosestHit.azshader"; - m_closestHitShader = RPI::LoadShader(closestHitShaderFilePath); + m_closestHitShader = RPI::LoadCriticalShader(closestHitShaderFilePath); auto closestHitShaderVariant = m_closestHitShader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId); RHI::PipelineStateDescriptorForRayTracing closestHitShaderDescriptor; @@ -72,7 +72,7 @@ namespace AZ // miss shader AZStd::string missShaderFilePath = "Shaders/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingMiss.azshader"; - m_missShader = RPI::LoadShader(missShaderFilePath); + m_missShader = RPI::LoadCriticalShader(missShaderFilePath); auto missShaderVariant = m_missShader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId); RHI::PipelineStateDescriptorForRayTracing missShaderDescriptor; diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.cpp index 56ae50069e..54cf9783cd 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.cpp @@ -42,7 +42,7 @@ namespace AZ // load shader // Note: the shader may not be available on all platforms AZStd::string shaderFilePath = "Shaders/DiffuseGlobalIllumination/DiffuseProbeGridRelocation.azshader"; - m_shader = RPI::LoadShader(shaderFilePath); + m_shader = RPI::LoadCriticalShader(shaderFilePath); if (m_shader == nullptr) { return; diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRenderPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRenderPass.cpp index 55d8ca5cba..a4cc101222 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRenderPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRenderPass.cpp @@ -30,7 +30,7 @@ namespace AZ // create the shader resource group // Note: the shader may not be available on all platforms AZStd::string shaderFilePath = "Shaders/DiffuseGlobalIllumination/DiffuseProbeGridRender.azshader"; - m_shader = RPI::LoadShader(shaderFilePath); + m_shader = RPI::LoadCriticalShader(shaderFilePath); if (m_shader == nullptr) { return; diff --git a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.cpp b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.cpp index 821b9c52b4..cd781390a3 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiPass.cpp @@ -446,7 +446,7 @@ namespace AZ } { - m_shader = RPI::LoadShader(ImguiShaderFilePath); + m_shader = RPI::LoadCriticalShader(ImguiShaderFilePath); m_pipelineState = aznew RPI::PipelineStateForDraw; m_pipelineState->Init(m_shader); diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp index a9078e1dd8..c0e25e3da9 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp @@ -487,7 +487,7 @@ namespace AZ RHI::DrawListTag& drawListTag) { // load shader - shader = RPI::LoadShader(filePath); + shader = RPI::LoadCriticalShader(filePath); AZ_Error("ReflectionProbeFeatureProcessor", shader, "Failed to find asset for shader [%s]", filePath); // store drawlist tag diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp index f0f947ba03..4f5caca108 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp @@ -52,7 +52,7 @@ namespace AZ // load shaders AZStd::string verticalBlurShaderFilePath = "Shaders/Reflections/ReflectionScreenSpaceBlurVertical.azshader"; - Data::Instance verticalBlurShader = RPI::LoadShader(verticalBlurShaderFilePath); + Data::Instance verticalBlurShader = RPI::LoadCriticalShader(verticalBlurShaderFilePath); if (verticalBlurShader == nullptr) { AZ_Error("PassSystem", false, "[ReflectionScreenSpaceBlurPass '%s']: Failed to load shader '%s'!", GetPathName().GetCStr(), verticalBlurShaderFilePath.c_str()); @@ -60,7 +60,7 @@ namespace AZ } AZStd::string horizontalBlurShaderFilePath = "Shaders/Reflections/ReflectionScreenSpaceBlurHorizontal.azshader"; - Data::Instance horizontalBlurShader = RPI::LoadShader(horizontalBlurShaderFilePath); + Data::Instance horizontalBlurShader = RPI::LoadCriticalShader(horizontalBlurShaderFilePath); if (horizontalBlurShader == nullptr) { AZ_Error("PassSystem", false, "[ReflectionScreenSpaceBlurPass '%s']: Failed to load shader '%s'!", GetPathName().GetCStr(), horizontalBlurShaderFilePath.c_str()); 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 e6d2bdad82..a2972ff0fd 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPIUtils.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPIUtils.h @@ -22,19 +22,21 @@ namespace AZ class Shader; //! Get the asset ID for a given shader file path - Data::AssetId GetShaderAssetId(const AZStd::string& shaderFilePath); + Data::AssetId GetShaderAssetId(const AZStd::string& shaderFilePath, bool isCritical = false); //! Finds a shader asset for the given shader asset ID. Optional shaderFilePath param for debugging. Data::Asset FindShaderAsset(Data::AssetId shaderAssetId, const AZStd::string& shaderFilePath = ""); //! Finds a shader asset for the given shader file path Data::Asset FindShaderAsset(const AZStd::string& shaderFilePath); + Data::Asset FindCriticalShaderAsset(const AZStd::string& shaderFilePath); //! Loads a shader for the given shader asset ID. Optional shaderFilePath param for debugging. Data::Instance LoadShader(Data::AssetId shaderAssetId, const AZStd::string& shaderFilePath = ""); //! Loads a shader for the given shader file path Data::Instance LoadShader(const AZStd::string& shaderFilePath); + Data::Instance LoadCriticalShader(const AZStd::string& shaderFilePath); //! Loads a streaming image asset for the given file path Data::Instance LoadStreamingTexture(AZStd::string_view path); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.cpp index f582f3ba04..a803ecf31a 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.cpp @@ -67,6 +67,7 @@ namespace AZ // --- Code related to dependency shader asset handling --- + // Helper class to pass parameters to the AddDependency and FindReferencedAssets functions below struct FindPassReferenceAssetParams { void* passAssetObject; @@ -77,50 +78,28 @@ namespace AZ const char* jobKey; // Job key for adding job dependency }; - //! Adds all relevant dependencies for a referenced source file, considering that the path might be relative to the original file location or a full asset path. - //! This will usually include multiple source dependencies and a single job dependency, but will include only source dependencies if the file is not found. - //! Note the AssetBuilderSDK::JobDependency::m_platformIdentifier will not be set by this function. The calling code must set this value before passing back - //! to the AssetBuilderSDK::CreateJobsResponse. - void AddPossibleDependencies( - FindPassReferenceAssetParams& params, - AssetBuilderSDK::CreateJobsResponse& response, - AssetBuilderSDK::JobDescriptor& job) + // Helper function to get a file reference and create a corresponding job dependency + void AddDependency(FindPassReferenceAssetParams& params, AssetBuilderSDK::JobDescriptor* job) { - bool dependencyFileFound = false; + AZStd::string_view& file = params.dependencySourceFile; + AZ::Data::AssetInfo sourceInfo; + AZStd::string watchFolder; + bool fileFound = false; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fileFound, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetSourceInfoBySourcePath, file.data(), sourceInfo, watchFolder); - AZStd::vector possibleDependencies = RPI::AssetUtils::GetPossibleDepenencyPaths(params.passAssetSourceFile, params.dependencySourceFile); - for (auto& file : possibleDependencies) + if (fileFound) { - AssetBuilderSDK::SourceFileDependency sourceFileDependency; - sourceFileDependency.m_sourceFileDependencyPath = file; - response.m_sourceFileDependencyList.push_back(sourceFileDependency); - - // The first path found is the highest priority, and will have a job dependency, as this is the one - // the builder will actually use - if (!dependencyFileFound) - { - AZ::Data::AssetInfo sourceInfo; - AZStd::string watchFolder; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(dependencyFileFound, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetSourceInfoBySourcePath, file.c_str(), sourceInfo, watchFolder); - - if (dependencyFileFound) - { - AssetBuilderSDK::JobDependency jobDependency; - jobDependency.m_jobKey = params.jobKey; - jobDependency.m_type = AssetBuilderSDK::JobDependencyType::Order; - jobDependency.m_sourceFile.m_sourceFileDependencyPath = file; - job.m_jobDependencyList.push_back(jobDependency); - } - } + AssetBuilderSDK::JobDependency jobDependency; + jobDependency.m_jobKey = params.jobKey; + jobDependency.m_type = AssetBuilderSDK::JobDependencyType::Order; + jobDependency.m_sourceFile.m_sourceFileDependencyPath = file; + job->m_jobDependencyList.push_back(jobDependency); + AZ_TracePrintf(PassBuilderName, "Creating job dependency on file [%s] \n", file.data()); } } // Helper function to find all assetId's and object references - bool FindPassReferencedAssets(FindPassReferenceAssetParams& params, - AZStd::unordered_set& referencedAssetList, - AssetBuilderSDK::CreateJobsResponse& response, - AssetBuilderSDK::JobDescriptor& job, - bool jobCreationPhase) + bool FindReferencedAssets(FindPassReferenceAssetParams& params, AssetBuilderSDK::JobDescriptor* job) { SerializeContext::ErrorHandler errorLogger; errorLogger.Reset(); @@ -141,10 +120,10 @@ namespace AZ const AZStd::string& path = assetReference->m_filePath; uint32_t subId = 0; - if (jobCreationPhase) + if (job != nullptr) // Create Job Phase { params.dependencySourceFile = path; - AddPossibleDependencies(params, response, job); + AddDependency(params, job); } else // Process Job Phase { @@ -161,12 +140,6 @@ namespace AZ } } } - - // If the asset ID is valid, add it as a dependency - if (assetReference->m_assetId.IsValid()) - { - referencedAssetList.insert(assetReference->m_assetId); - } } return true; }; @@ -196,15 +169,16 @@ namespace AZ void PassBuilder::CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response) const { + // --- Handle shutdown case --- + if (m_isShuttingDown) { response.m_result = AssetBuilderSDK::CreateJobsResultCode::ShuttingDown; return; } - AssetBuilderSDK::JobDescriptor job; + // --- Get serialization context --- - // Get serialization context SerializeContext* serializeContext = nullptr; ComponentApplicationBus::BroadcastResult(serializeContext, &ComponentApplicationBus::Events::GetSerializeContext); if (!serializeContext) @@ -213,7 +187,8 @@ namespace AZ return; } - // Load PassAsset + // --- Load PassAsset --- + AZStd::string fullPath; AzFramework::StringFunc::Path::ConstructFull(request.m_watchFolder.c_str(), request.m_sourceFile.c_str(), fullPath, true); @@ -227,7 +202,12 @@ namespace AZ return; } - // Find all Asset IDs we depend on + AssetBuilderSDK::JobDescriptor job; + job.m_jobKey = PassBuilderJobKey; + job.m_critical = true; // Passes are a critical part of the rendering system + + // --- Find all dependencies --- + AZStd::unordered_set dependentList; Uuid passAssetUuid = AzTypeInfo::Uuid(); @@ -238,30 +218,30 @@ namespace AZ params.serializeContext = serializeContext; params.jobKey = "Shader Asset"; - if (!FindPassReferencedAssets(params, dependentList, response, job, true)) + if (!FindReferencedAssets(params, &job)) { return; } + // --- Create a job per platform --- + for (const AssetBuilderSDK::PlatformInfo& platformInfo : request.m_enabledPlatforms) { - job.m_jobKey = PassBuilderJobKey; + for (auto& jobDependency : job.m_jobDependencyList) + { + jobDependency.m_platformIdentifier = platformInfo.m_identifier.c_str(); + } job.SetPlatformIdentifier(platformInfo.m_identifier.c_str()); - - // Passes are a critical part of the rendering system - job.m_critical = true; - response.m_createJobOutputs.push_back(job); } response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success; } - - void PassBuilder::ProcessJob(const AssetBuilderSDK::ProcessJobRequest& request, AssetBuilderSDK::ProcessJobResponse& response) const { - // Handle job cancellation and shutdown cases + // --- Handle job cancellation and shutdown cases --- + AssetBuilderSDK::JobCancelListener jobCancelListener(request.m_jobId); if (jobCancelListener.IsCancelled() || m_isShuttingDown) { @@ -269,7 +249,8 @@ namespace AZ return; } - // Get serialization context + // --- Get serialization context --- + SerializeContext* serializeContext = nullptr; ComponentApplicationBus::BroadcastResult(serializeContext, &ComponentApplicationBus::Events::GetSerializeContext); if (!serializeContext) @@ -278,7 +259,8 @@ namespace AZ return; } - // Load PassAsset + // --- Load PassAsset --- + PassAsset passAsset; AZ::Outcome loadResult = JsonSerializationUtils::LoadObjectFromFile(passAsset, request.m_fullPath); @@ -289,8 +271,8 @@ namespace AZ return; } - // Find all Asset IDs we depend on - AZStd::unordered_set dependentList; + // --- Find all dependencies --- + Uuid passAssetUuid = AzTypeInfo::Uuid(); FindPassReferenceAssetParams params; @@ -300,21 +282,20 @@ namespace AZ params.serializeContext = serializeContext; params.jobKey = "Shader Asset"; - AssetBuilderSDK::CreateJobsResponse dummyResponse; - AssetBuilderSDK::JobDescriptor dummyJob; - - if (!FindPassReferencedAssets(params, dependentList, dummyResponse, dummyJob, false)) + if (!FindReferencedAssets(params, nullptr)) { return; } - // Get destination file name and path + // --- Get destination file name and path --- + AZStd::string destFileName; AZStd::string destPath; AzFramework::StringFunc::Path::GetFullFileName(request.m_fullPath.c_str(), destFileName); AzFramework::StringFunc::Path::ConstructFull(request.m_tempDirPath.c_str(), destFileName.c_str(), destPath, true); - // Save the asset to binary format for production + // --- Save the asset to binary format for production --- + bool result = Utils::SaveObjectToFile(destPath, DataStream::ST_BINARY, &passAsset, passAssetUuid, serializeContext); if (result == false) { @@ -322,14 +303,10 @@ namespace AZ return; } - // Success. Save output product(s) to response - AssetBuilderSDK::JobProduct jobProduct(destPath, PassAsset::RTTI_Type(), 0); - for (auto& assetId : dependentList) - { - jobProduct.m_dependencies.emplace_back(AssetBuilderSDK::ProductDependency(assetId, 0)); - } + // --- Save output product(s) to response --- - jobProduct.m_dependenciesHandled = true; // We've output the dependencies immediately above so it's OK to tell the AP we've handled dependencies + AssetBuilderSDK::JobProduct jobProduct(destPath, PassAsset::RTTI_Type(), 0); + jobProduct.m_dependenciesHandled = true; response.m_outputProducts.push_back(jobProduct); response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success; } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/AttachmentReadback.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/AttachmentReadback.cpp index 29a17dc9a8..29af8b7b63 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/AttachmentReadback.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/AttachmentReadback.cpp @@ -121,7 +121,7 @@ namespace AZ // Load shader and srg const char* ShaderPath = "shader/decomposemsimage.azshader"; - m_decomposeShader = LoadShader(ShaderPath); + m_decomposeShader = LoadCriticalShader(ShaderPath); if (m_decomposeShader == nullptr) { diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RPIUtils.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RPIUtils.cpp index ebccc87cac..9173b47fad 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RPIUtils.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RPIUtils.cpp @@ -8,6 +8,7 @@ #include +#include #include #include @@ -20,7 +21,7 @@ namespace AZ namespace RPI { - Data::AssetId GetShaderAssetId(const AZStd::string& shaderFilePath) + Data::AssetId GetShaderAssetId(const AZStd::string& shaderFilePath, bool isCritical) { Data::AssetId shaderAssetId; @@ -34,6 +35,19 @@ namespace AZ if (!shaderAssetId.IsValid()) { + if (isCritical) + { + Data::Asset shaderAsset = RPI::AssetUtils::LoadCriticalAsset(shaderFilePath); + if (shaderAsset.IsReady()) + { + return shaderAsset.GetId(); + } + else + { + AZ_Error("RPI Utils", false, "Could not load critical shader [%s]", shaderFilePath.c_str()); + } + } + AZ_Error("RPI Utils", false, "Failed to get asset id for shader [%s]", shaderFilePath.c_str()); } @@ -83,11 +97,23 @@ namespace AZ return FindShaderAsset(GetShaderAssetId(shaderFilePath), shaderFilePath); } + Data::Asset FindCriticalShaderAsset(const AZStd::string& shaderFilePath) + { + const bool isCritical = true; + return FindShaderAsset(GetShaderAssetId(shaderFilePath, isCritical), shaderFilePath); + } + Data::Instance LoadShader(const AZStd::string& shaderFilePath) { return LoadShader(GetShaderAssetId(shaderFilePath), shaderFilePath); } + Data::Instance LoadCriticalShader(const AZStd::string& shaderFilePath) + { + const bool isCritical = true; + return LoadShader(GetShaderAssetId(shaderFilePath, isCritical), shaderFilePath); + } + AZ::Data::Instance LoadStreamingTexture(AZStd::string_view path) { AzFramework::AssetSystem::AssetStatus status = AzFramework::AssetSystem::AssetStatus_Unknown; diff --git a/Gems/LyShine/Code/Source/Draw2d.cpp b/Gems/LyShine/Code/Source/Draw2d.cpp index 2d3612fc07..b4c8d58fae 100644 --- a/Gems/LyShine/Code/Source/Draw2d.cpp +++ b/Gems/LyShine/Code/Source/Draw2d.cpp @@ -79,7 +79,7 @@ void CDraw2d::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapSc // Load the shader to be used for 2d drawing const char* shaderFilepath = "Shaders/SimpleTextured.azshader"; - AZ::Data::Instance shader = AZ::RPI::LoadShader(shaderFilepath); + AZ::Data::Instance shader = AZ::RPI::LoadCriticalShader(shaderFilepath); // Set scene to be associated with the dynamic draw context AZ::RPI::ScenePtr scene; diff --git a/Gems/LyShine/Code/Source/UiRenderer.cpp b/Gems/LyShine/Code/Source/UiRenderer.cpp index 357431c80a..c52c249d20 100644 --- a/Gems/LyShine/Code/Source/UiRenderer.cpp +++ b/Gems/LyShine/Code/Source/UiRenderer.cpp @@ -58,7 +58,7 @@ void UiRenderer::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstra // Load the UI shader const char* uiShaderFilepath = "Shaders/LyShineUI.azshader"; - AZ::Data::Instance uiShader = AZ::RPI::LoadShader(uiShaderFilepath); + AZ::Data::Instance uiShader = AZ::RPI::LoadCriticalShader(uiShaderFilepath); // Create scene to be used by the dynamic draw context if (m_viewportContext) From 39d56a8834c7aa08db5b0c7ac1b2b507bedf40f8 Mon Sep 17 00:00:00 2001 From: antonmic <56370189+antonmic@users.noreply.github.com> Date: Wed, 11 Aug 2021 10:45:48 -0700 Subject: [PATCH 23/70] Removing product dependency check from pass builder test since shaders references are now registered as a job dependency and not a product dependency Signed-off-by: antonmic <56370189+antonmic@users.noreply.github.com> --- Gems/Atom/RPI/Code/Tests.Builders/PassBuilderTest.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/Gems/Atom/RPI/Code/Tests.Builders/PassBuilderTest.cpp b/Gems/Atom/RPI/Code/Tests.Builders/PassBuilderTest.cpp index ad1df41824..4e088cece5 100644 --- a/Gems/Atom/RPI/Code/Tests.Builders/PassBuilderTest.cpp +++ b/Gems/Atom/RPI/Code/Tests.Builders/PassBuilderTest.cpp @@ -112,9 +112,6 @@ namespace UnitTest EXPECT_TRUE(response.m_resultCode == AssetBuilderSDK::ProcessJobResult_Success); EXPECT_TRUE(response.m_outputProducts.size() == 1); - // Verify the dependency was registered - EXPECT_TRUE(response.m_outputProducts[0].m_dependencies.size() == 1); - // Verify input and output names are the same Data::Asset readAsset = LoadAssetFromFile(response.m_outputProducts[0].m_productFileName.c_str()); RPI::PassAsset* readPassAsset = static_cast(readAsset.GetData()); From ce7598c10bbc615ba3a954e6bdbfd7ced16c9e61 Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Wed, 11 Aug 2021 12:59:32 -0700 Subject: [PATCH 24/70] [redcode/crythread-2nd-pass] fixed missing includes Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Code/LauncherUnified/Platform/Linux/Launcher_Linux.cpp | 1 + Code/LauncherUnified/Platform/Mac/Launcher_Mac.mm | 2 ++ Code/Legacy/CryCommon/VectorMap.h | 1 + .../AtomFont/Code/Include/AtomLyIntegration/AtomFont/AtomFont.h | 2 +- 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Code/LauncherUnified/Platform/Linux/Launcher_Linux.cpp b/Code/LauncherUnified/Platform/Linux/Launcher_Linux.cpp index 1e87b902a6..3030dcc740 100644 --- a/Code/LauncherUnified/Platform/Linux/Launcher_Linux.cpp +++ b/Code/LauncherUnified/Platform/Linux/Launcher_Linux.cpp @@ -10,6 +10,7 @@ #include #include // for AZ_MAX_PATH_LEN +#include #include diff --git a/Code/LauncherUnified/Platform/Mac/Launcher_Mac.mm b/Code/LauncherUnified/Platform/Mac/Launcher_Mac.mm index cfba0d8aac..f4ea67c6e6 100644 --- a/Code/LauncherUnified/Platform/Mac/Launcher_Mac.mm +++ b/Code/LauncherUnified/Platform/Mac/Launcher_Mac.mm @@ -11,6 +11,8 @@ #include <../Common/Apple/Launcher_Apple.h> #include <../Common/UnixLike/Launcher_UnixLike.h> +#include + #if AZ_TESTS_ENABLED int main(int argc, char* argv[]) diff --git a/Code/Legacy/CryCommon/VectorMap.h b/Code/Legacy/CryCommon/VectorMap.h index 1a42f0e48f..ee99c6f952 100644 --- a/Code/Legacy/CryCommon/VectorMap.h +++ b/Code/Legacy/CryCommon/VectorMap.h @@ -14,6 +14,7 @@ #define CRYINCLUDE_CRYCOMMON_VECTORMAP_H #pragma once +#include // for stl::free_container //-------------------------------------------------------------------------- // VectorMap diff --git a/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/AtomFont.h b/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/AtomFont.h index 7dd2629bd0..018bc74877 100644 --- a/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/AtomFont.h +++ b/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/AtomFont.h @@ -96,7 +96,7 @@ namespace AZ void UnregisterFont(const char* fontName); private: - using FontMap = std::unordered_map; + using FontMap = AZStd::unordered_map; using FontMapItor = FontMap::iterator; using FontMapConstItor = FontMap::const_iterator; From 8b8e249e05852e4d2d6da1435df7275f92f894f6 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Wed, 11 Aug 2021 13:59:41 -0700 Subject: [PATCH 25/70] Add new functions to mock unit test class. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../AzCore/AzCore/UnitTest/Mocks/MockSettingsRegistry.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Code/Framework/AzCore/AzCore/UnitTest/Mocks/MockSettingsRegistry.h b/Code/Framework/AzCore/AzCore/UnitTest/Mocks/MockSettingsRegistry.h index 7c132b29a3..a63e782146 100644 --- a/Code/Framework/AzCore/AzCore/UnitTest/Mocks/MockSettingsRegistry.h +++ b/Code/Framework/AzCore/AzCore/UnitTest/Mocks/MockSettingsRegistry.h @@ -25,6 +25,10 @@ namespace AZ MOCK_CONST_METHOD2(Visit, bool(const VisitorCallback&, AZStd::string_view)); MOCK_METHOD1(RegisterNotifier, NotifyEventHandler(const NotifyCallback&)); MOCK_METHOD1(RegisterNotifier, NotifyEventHandler(NotifyCallback&&)); + MOCK_METHOD1(RegisterPreMergeEvent, PreMergeEventHandler(const PreMergeEventCallback&)); + MOCK_METHOD1(RegisterPreMergeEvent, PreMergeEventHandler(PreMergeEventCallback&&)); + MOCK_METHOD1(PostMergeEventHandler, PreMergeEventHandler(const PostMergeEventCallback&)); + MOCK_METHOD1(PostMergeEventHandler, PreMergeEventHandler(PostMergeEventCallback&&)); MOCK_CONST_METHOD2(Get, bool(bool&, AZStd::string_view)); MOCK_CONST_METHOD2(Get, bool(s64&, AZStd::string_view)); From 6c83dcd702ed015d9f6d6a3b08685a4f59752673 Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Wed, 11 Aug 2021 15:44:04 -0700 Subject: [PATCH 26/70] [redcode/crythread-2nd-pass] fixed another missing include Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Code/LauncherUnified/Platform/Windows/Launcher_Windows.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Code/LauncherUnified/Platform/Windows/Launcher_Windows.cpp b/Code/LauncherUnified/Platform/Windows/Launcher_Windows.cpp index 5cc3070cdb..44426f6d01 100644 --- a/Code/LauncherUnified/Platform/Windows/Launcher_Windows.cpp +++ b/Code/LauncherUnified/Platform/Windows/Launcher_Windows.cpp @@ -9,6 +9,7 @@ #include #include +#include int APIENTRY WinMain([[maybe_unused]] HINSTANCE hInstance, [[maybe_unused]] HINSTANCE hPrevInstance, [[maybe_unused]] LPSTR lpCmdLine, [[maybe_unused]] int nCmdShow) { From 5a891c8cbdd769744a75c1118b6445199ce249fd Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Wed, 11 Aug 2021 15:54:59 -0700 Subject: [PATCH 27/70] [redcode/crythread-2nd-pass] replaced remaining CrySpinLock/CryWriteLock usage with equivalent AZStd version Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Code/Legacy/CryCommon/Synchronization.h | 33 ++++-------------------- Code/Legacy/CryCommon/physinterface.h | 6 +++-- Code/Legacy/CrySystem/DebugCallStack.cpp | 7 ++--- 3 files changed, 13 insertions(+), 33 deletions(-) diff --git a/Code/Legacy/CryCommon/Synchronization.h b/Code/Legacy/CryCommon/Synchronization.h index 3bac215998..d38160c967 100644 --- a/Code/Legacy/CryCommon/Synchronization.h +++ b/Code/Legacy/CryCommon/Synchronization.h @@ -21,7 +21,7 @@ // //--------------------------------------------------------------------------- -#include "MultiThread.h" +#include namespace stl { @@ -51,43 +51,20 @@ namespace stl struct PSyncMultiThread { - PSyncMultiThread() - : _Semaphore(0) {} + PSyncMultiThread() {} void Lock() { - CryWriteLock(&_Semaphore); + m_lock.lock(); } void Unlock() { - CryReleaseWriteLock(&_Semaphore); - } - int IsLocked() const volatile - { - return _Semaphore; + m_lock.unlock(); } private: - volatile int _Semaphore; + AZStd::spin_mutex m_lock; }; - -#ifdef _DEBUG - - struct PSyncDebug - : public PSyncMultiThread - { - void Lock() - { - assert(!IsLocked()); - PSyncMultiThread::Lock(); - } - }; - -#else - - typedef PSyncNone PSyncDebug; - -#endif }; #endif // CRYINCLUDE_CRYCOMMON_SYNCHRONIZATION_H diff --git a/Code/Legacy/CryCommon/physinterface.h b/Code/Legacy/CryCommon/physinterface.h index 89b7318eaa..b1aaa5aef4 100644 --- a/Code/Legacy/CryCommon/physinterface.h +++ b/Code/Legacy/CryCommon/physinterface.h @@ -26,6 +26,8 @@ #include +#include + ////////////////////////////////////////////////////////////////////////// // Physics defines. ////////////////////////////////////////////////////////////////////////// @@ -2834,8 +2836,8 @@ struct IGeometry virtual int PointInsideStatus(const Vec3& pt) = 0; // for meshes, will create an auxiliary hashgrid for acceleration // IntersectLocked - the main function for geomtries. pdata1,pdata2,pparams can be 0 - defaults will be assumed. // returns a pointer to an internal thread-specific contact buffer, locked with the lock argument - virtual int IntersectLocked(IGeometry* pCollider, geom_world_data* pdata1, geom_world_data* pdata2, intersection_params* pparams, geom_contact*& pcontacts, WriteLockCond& lock) = 0; - virtual int IntersectLocked(IGeometry* pCollider, geom_world_data* pdata1, geom_world_data* pdata2, intersection_params* pparams, geom_contact*& pcontacts, WriteLockCond& lock, int iCaller) = 0; + virtual int IntersectLocked(IGeometry* pCollider, geom_world_data* pdata1, geom_world_data* pdata2, intersection_params* pparams, geom_contact*& pcontacts, AZStd::spin_mutex& lock) = 0; + virtual int IntersectLocked(IGeometry* pCollider, geom_world_data* pdata1, geom_world_data* pdata2, intersection_params* pparams, geom_contact*& pcontacts, AZStd::spin_mutex& lock, int iCaller) = 0; // Intersect - same as Intersect, but doesn't lock pcontacts virtual int Intersect(IGeometry* pCollider, geom_world_data* pdata1, geom_world_data* pdata2, intersection_params* pparams, geom_contact*& pcontacts) = 0; // FindClosestPoint - for non-convex meshes only does local search, doesn't guarantee global minimum diff --git a/Code/Legacy/CrySystem/DebugCallStack.cpp b/Code/Legacy/CrySystem/DebugCallStack.cpp index 576c3ee9fb..a043f16756 100644 --- a/Code/Legacy/CrySystem/DebugCallStack.cpp +++ b/Code/Legacy/CrySystem/DebugCallStack.cpp @@ -18,6 +18,7 @@ #include #include +#include #define VS_VERSION_INFO 1 #define IDD_CRITICAL_ERROR 101 @@ -152,13 +153,13 @@ void DebugCallStack::SetUserDialogEnable(const bool bUserDialogEnable) DWORD g_idDebugThreads[10]; const char* g_nameDebugThreads[10]; int g_nDebugThreads = 0; -volatile int g_lockThreadDumpList = 0; +AZStd::spin_mutex g_lockThreadDumpList = 0; void MarkThisThreadForDebugging(const char* name) { EBUS_EVENT(AZ::Debug::EventTraceDrillerSetupBus, SetThreadName, AZStd::this_thread::get_id(), name); - WriteLock lock(g_lockThreadDumpList); + AZStd::lock_guard lock(g_lockThreadDumpList); DWORD id = GetCurrentThreadId(); if (g_nDebugThreads == sizeof(g_idDebugThreads) / sizeof(g_idDebugThreads[0])) { @@ -178,7 +179,7 @@ void MarkThisThreadForDebugging(const char* name) void UnmarkThisThreadFromDebugging() { - WriteLock lock(g_lockThreadDumpList); + AZStd::lock_guard lock(g_lockThreadDumpList); DWORD id = GetCurrentThreadId(); for (int i = g_nDebugThreads - 1; i >= 0; i--) { From 337ea488b6539ced5d2e9bf2518b52c93b8fdf56 Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Wed, 11 Aug 2021 15:57:49 -0700 Subject: [PATCH 28/70] [redcode/crythread-2nd-pass] replaced remaining CryInterlocked* usage with equivalent AZStd version Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Code/Legacy/CryCommon/IFunctorBase.h | 8 +++-- Code/Legacy/CryCommon/smartptr.h | 36 ++++++++----------- .../Code/Source/Engine/AudioRequests.cpp | 2 +- 3 files changed, 20 insertions(+), 26 deletions(-) diff --git a/Code/Legacy/CryCommon/IFunctorBase.h b/Code/Legacy/CryCommon/IFunctorBase.h index 2a8af50d33..c7d39ee923 100644 --- a/Code/Legacy/CryCommon/IFunctorBase.h +++ b/Code/Legacy/CryCommon/IFunctorBase.h @@ -15,6 +15,8 @@ #pragma once +#include + // Base class for functor storage. // Not intended for direct usage. class IFunctorBase @@ -27,19 +29,19 @@ public: void AddRef() { - CryInterlockedIncrement(&m_nReferences); + m_nReferences.fetch_add(1, AZStd::memory_order_acq_rel); } void Release() { - if (CryInterlockedDecrement(&m_nReferences) <= 0) + if (m_nReferences.fetch_sub(1, AZStd::memory_order_acq_rel) == 1) { delete this; } } protected: - volatile int m_nReferences; + AZStd::atomic_int m_nReferences; }; // Base Template for specialization. diff --git a/Code/Legacy/CryCommon/smartptr.h b/Code/Legacy/CryCommon/smartptr.h index 246e18d541..fd833b12e3 100644 --- a/Code/Legacy/CryCommon/smartptr.h +++ b/Code/Legacy/CryCommon/smartptr.h @@ -18,6 +18,9 @@ void CryFatalError(const char*, ...) PRINTF_PARAMS(1, 2); #if defined(APPLE) #include #endif + +#include + ////////////////////////////////////////////////////////////////// // SMART POINTER ////////////////////////////////////////////////////////////////// @@ -352,38 +355,32 @@ protected: class CMultiThreadRefCount { public: - CMultiThreadRefCount() - : m_cnt(0) {} + CMultiThreadRefCount() {} virtual ~CMultiThreadRefCount() {} inline int AddRef() { - return CryInterlockedIncrement(&m_cnt); + return m_count.fetch_add(1, AZStd::memory_order_acq_rel) + 1; // because we get the original value back } inline int Release() { - const int nCount = CryInterlockedDecrement(&m_cnt); - assert(nCount >= 0); + const int nCount = m_count.fetch_sub(1, AZStd::memory_order_acq_rel) - 1; // because we get the original value back + AZ_Assert(nCount >= 0, "Deleting Reference Counted Object Twice"); if (nCount == 0) { delete this; } - else if (nCount < 0) - { - assert(0); - CryFatalError("Deleting Reference Counted Object Twice"); - } return nCount; } - inline int GetRefCount() const { return m_cnt; } + inline int GetRefCount() const { return m_count.load(AZStd::memory_order_acquire); } protected: // Allows the memory for the object to be deallocated in the dynamic module where it was originally constructed, as it may use different memory manager (Debug/Release configurations) virtual void DeleteThis() { delete this; } private: - volatile int m_cnt; + AZStd::atomic_int m_count{ 0 }; }; // base class for interfaces implementing reference counting that needs to be thread-safe @@ -404,29 +401,24 @@ public: virtual void AddRef() { - CryInterlockedIncrement(&m_nRefCounter); + m_nRefCounter.fetch_add(1, AZStd::memory_order_acq_rel); } virtual void Release() { - const int nCount = CryInterlockedDecrement(&m_nRefCounter); - assert(nCount >= 0); + const int nCount = m_nRefCounter.fetch_sub(1, AZStd::memory_order_acq_rel) - 1; // because we get the original value back + AZ_Assert(nCount >= 0, "Deleting Reference Counted Object Twice"); if (nCount == 0) { delete this; } - else if (nCount < 0) - { - assert(0); - CryFatalError("Deleting Reference Counted Object Twice"); - } } - Counter NumRefs() const { return m_nRefCounter; } + Counter NumRefs() const { return m_nRefCounter.load(AZStd::memory_order_acquire); } protected: - volatile Counter m_nRefCounter; + AZStd::atomic m_nRefCounter{ 0 }; }; typedef _i_reference_target _i_reference_target_t; diff --git a/Gems/AudioSystem/Code/Source/Engine/AudioRequests.cpp b/Gems/AudioSystem/Code/Source/Engine/AudioRequests.cpp index 35da74b0de..0862483ab8 100644 --- a/Gems/AudioSystem/Code/Source/Engine/AudioRequests.cpp +++ b/Gems/AudioSystem/Code/Source/Engine/AudioRequests.cpp @@ -153,7 +153,7 @@ namespace Audio /////////////////////////////////////////////////////////////////////////////////////////////////// void SAudioRequestDataInternal::Release() { - const int nCount = CryInterlockedDecrement(&m_nRefCounter); + const int nCount = m_nRefCounter.fetch_sub(1, AZStd::memory_order_acq_rel) - 1; // because we get the original value back AZ_Assert(nCount >= 0, "AudioRequests Release - Decremented reference counter too many times!"); if (nCount == 0) From c173dee2bcf8c348babdb93b1ea9368b0027050b Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Wed, 11 Aug 2021 16:38:54 -0700 Subject: [PATCH 29/70] [redcode/crythread-2nd-pass] removed MultiThread.h along with external CryInterlocked* definitions Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Code/Legacy/CryCommon/MultiThread.h | 277 -------------------- Code/Legacy/CryCommon/WinBase.cpp | 85 +----- Code/Legacy/CryCommon/crycommon_files.cmake | 1 - Code/Legacy/CryCommon/platform.h | 4 - Code/Legacy/CryCommon/platform_impl.cpp | 52 ---- Code/Legacy/CrySystem/Log.h | 1 - 6 files changed, 1 insertion(+), 419 deletions(-) delete mode 100644 Code/Legacy/CryCommon/MultiThread.h diff --git a/Code/Legacy/CryCommon/MultiThread.h b/Code/Legacy/CryCommon/MultiThread.h deleted file mode 100644 index c3aa892d14..0000000000 --- a/Code/Legacy/CryCommon/MultiThread.h +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - - -#pragma once - -#if defined(APPLE) || defined(LINUX) -#include -#endif - -#include - -#include "CryAssert.h" - -// Section dictionary -#if defined(AZ_RESTRICTED_PLATFORM) -#define MULTITHREAD_H_SECTION_TRAITS 1 -#define MULTITHREAD_H_SECTION_DEFINE_CRYINTERLOCKEXCHANGE 2 -#define MULTITHREAD_H_SECTION_IMPLEMENT_CRYSPINLOCK 3 -#define MULTITHREAD_H_SECTION_IMPLEMENT_CRYINTERLOCKEDADD 4 -#define MULTITHREAD_H_SECTION_IMPLEMENT_CRYINTERLOCKEDADDSIZE 5 -#define MULTITHREAD_H_SECTION_CRYINTERLOCKEDFLUSHSLIST_PT1 6 -#define MULTITHREAD_H_SECTION_CRYINTERLOCKEDFLUSHSLIST_PT2 7 -#define MULTITHREAD_H_SECTION_IMPLEMENT_CRYINTERLOCKEDCOMPAREEXCHANGE64 8 -#endif - -#define WRITE_LOCK_VAL (1 << 16) - -// Traits -#if defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION MULTITHREAD_H_SECTION_TRAITS - #include AZ_RESTRICTED_FILE(MultiThread_h) -#endif - -void CrySpinLock(volatile int* pLock, int checkVal, int setVal); -void CryReleaseSpinLock (volatile int*, int); - -LONG CryInterlockedIncrement(int volatile* lpAddend); -LONG CryInterlockedDecrement(int volatile* lpAddend); -LONG CryInterlockedOr(LONG volatile* Destination, LONG Value); -LONG CryInterlockedExchangeAdd(LONG volatile* lpAddend, LONG Value); -LONG CryInterlockedCompareExchange(LONG volatile* dst, LONG exchange, LONG comperand); -void* CryInterlockedCompareExchangePointer(void* volatile* dst, void* exchange, void* comperand); -void* CryInterlockedExchangePointer (void* volatile* dst, void* exchange); - -#if defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION MULTITHREAD_H_SECTION_DEFINE_CRYINTERLOCKEXCHANGE - #include AZ_RESTRICTED_FILE(MultiThread_h) -#endif - -ILINE void CrySpinLock(volatile int* pLock, int checkVal, int setVal) -{ -#ifdef _CPU_X86 -# ifdef __GNUC__ - int val; - __asm__ __volatile__ ( - "0: mov %[checkVal], %%eax\n" - " lock cmpxchg %[setVal], (%[pLock])\n" - " jnz 0b" - : "=m" (*pLock) - : [pLock] "r" (pLock), "m" (*pLock), - [checkVal] "m" (checkVal), - [setVal] "r" (setVal) - : "eax", "cc", "memory" - ); -# else //!__GNUC__ - __asm - { - mov edx, setVal - mov ecx, pLock -Spin: - // Trick from Intel Optimizations guide -#ifdef _CPU_SSE - pause -#endif - mov eax, checkVal - lock cmpxchg [ecx], edx - jnz Spin - } -# endif //!__GNUC__ -#else // !_CPU_X86 -# if defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION MULTITHREAD_H_SECTION_IMPLEMENT_CRYSPINLOCK - #include AZ_RESTRICTED_FILE(MultiThread_h) -# endif -# if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) -# undef AZ_RESTRICTED_SECTION_IMPLEMENTED -# elif defined(APPLE) || defined(LINUX) - // register int val; - // __asm__ __volatile__ ( - // "0: mov %[checkVal], %%eax\n" - // " lock cmpxchg %[setVal], (%[pLock])\n" - // " jnz 0b" - // : "=m" (*pLock) - // : [pLock] "r" (pLock), "m" (*pLock), - // [checkVal] "m" (checkVal), - // [setVal] "r" (setVal) - // : "eax", "cc", "memory" - // ); - //while(CryInterlockedCompareExchange((volatile long*)pLock,setVal,checkVal)!=checkVal) ; - uint loops = 0; - while (__sync_val_compare_and_swap((volatile int32_t*)pLock, (int32_t)checkVal, (int32_t)setVal) != checkVal) - { -# if !defined (ANDROID) && !defined(IOS) - _mm_pause(); -# endif - - if (!(++loops & 0x7F)) - { - usleep(1); // give threads with other prio chance to run - } - else if (!(loops & 0x3F)) - { - sched_yield(); // give threads with same prio chance to run - } - } -# else - // NOTE: The code below will fail on 64bit architectures! - while (_InterlockedCompareExchange((volatile LONG*)pLock, setVal, checkVal) != checkVal) - { - _mm_pause(); - } -# endif -#endif -} - -ILINE void CryReleaseSpinLock(volatile int* pLock, int setVal) -{ - *pLock = setVal; -} - -////////////////////////////////////////////////////////////////////////// -ILINE void CryInterlockedAdd(volatile int* pVal, int iAdd) -{ -#ifdef _CPU_X86 -# ifdef __GNUC__ - __asm__ __volatile__ ( - " lock add %[iAdd], (%[pVal])\n" - : "=m" (*pVal) - : [pVal] "r" (pVal), "m" (*pVal), [iAdd] "r" (iAdd) - ); -# else - __asm - { - mov edx, pVal - mov eax, iAdd - lock add [edx], eax - } -# endif -#else - // NOTE: The code below will fail on 64bit architectures! -#if defined(_WIN64) - _InterlockedExchangeAdd((volatile LONG*)pVal, iAdd); -#define AZ_RESTRICTED_SECTION_IMPLEMENTED -#elif defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION MULTITHREAD_H_SECTION_IMPLEMENT_CRYINTERLOCKEDADD - #include AZ_RESTRICTED_FILE(MultiThread_h) -#endif -#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) -#undef AZ_RESTRICTED_SECTION_IMPLEMENTED -#elif defined(APPLE) || defined(LINUX) - CryInterlockedExchangeAdd((volatile LONG*)pVal, iAdd); -#elif defined(APPLE) - OSAtomicAdd32(iAdd, (volatile LONG*)pVal); -#else - InterlockedExchangeAdd((volatile LONG*)pVal, iAdd); -#endif - -#endif -} - -ILINE void CryInterlockedAddSize(volatile size_t* pVal, ptrdiff_t iAdd) -{ -#if defined(PLATFORM_64BIT) -#if defined(_WIN64) - _InterlockedExchangeAdd64((volatile __int64*)pVal, iAdd); -#define AZ_RESTRICTED_SECTION_IMPLEMENTED -#elif defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION MULTITHREAD_H_SECTION_IMPLEMENT_CRYINTERLOCKEDADDSIZE - #include AZ_RESTRICTED_FILE(MultiThread_h) -#endif -#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) -#undef AZ_RESTRICTED_SECTION_IMPLEMENTED -#elif defined(WIN32) - InterlockedExchangeAdd64((volatile LONG64*)pVal, iAdd); -#elif defined(APPLE) || defined(LINUX) - (void)__sync_fetch_and_add((int64_t*)pVal, (int64_t)iAdd); -#else - int64 x, n; - do - { - x = (int64) * pVal; - n = x + iAdd; - } - while (CryInterlockedCompareExchange64((volatile int64*)pVal, n, x) != x); -#endif -#else - CryInterlockedAdd((volatile int*)pVal, (int)iAdd); -#endif -} - - - -////////////////////////////////////////////////////////////////////////// -ILINE void CryWriteLock(volatile int* rw) -{ - CrySpinLock(rw, 0, WRITE_LOCK_VAL); -} - -ILINE void CryReleaseWriteLock(volatile int* rw) -{ - CryInterlockedAdd(rw, -WRITE_LOCK_VAL); -} - -////////////////////////////////////////////////////////////////////////// -struct WriteLock -{ - ILINE WriteLock(volatile int& rw) { CryWriteLock(&rw); prw = &rw; } - ~WriteLock() { CryReleaseWriteLock(prw); } -private: - volatile int* prw; -}; - -////////////////////////////////////////////////////////////////////////// -struct WriteLockCond -{ - ILINE WriteLockCond(volatile int& rw, int bActive = 1) - { - if (bActive) - { - CrySpinLock(&rw, 0, iActive = WRITE_LOCK_VAL); - } - else - { - iActive = 0; - } - prw = &rw; - } - ILINE WriteLockCond() { prw = &(iActive = 0); } - ~WriteLockCond() - { - CryInterlockedAdd(prw, -iActive); - } - void SetActive(int bActive = 1) { iActive = -bActive & WRITE_LOCK_VAL; } - void Release() { CryInterlockedAdd(prw, -iActive); } - volatile int* prw; - int iActive; -}; - - -#if defined(LINUX) || defined(APPLE) -ILINE int64 CryInterlockedCompareExchange64(volatile int64* addr, int64 exchange, int64 comperand) -{ - return __sync_val_compare_and_swap(addr, comperand, exchange); - // This is OK, because long is signed int64 on Linux x86_64 - //return CryInterlockedCompareExchange((volatile long*)addr, (long)exchange, (long)comperand); -} -#else -ILINE int64 CryInterlockedCompareExchange64(volatile int64* addr, int64 exchange, int64 compare) -{ - // forward to system call -#if defined(AZ_RESTRICTED_PLATFORM) - #define AZ_RESTRICTED_SECTION MULTITHREAD_H_SECTION_IMPLEMENT_CRYINTERLOCKEDCOMPAREEXCHANGE64 - #include AZ_RESTRICTED_FILE(MultiThread_h) -#endif -#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) -#undef AZ_RESTRICTED_SECTION_IMPLEMENTED -#else - return _InterlockedCompareExchange64((volatile int64*)addr, exchange, compare); -#endif -} -#endif diff --git a/Code/Legacy/CryCommon/WinBase.cpp b/Code/Legacy/CryCommon/WinBase.cpp index 15146fbac1..a11787fef0 100644 --- a/Code/Legacy/CryCommon/WinBase.cpp +++ b/Code/Legacy/CryCommon/WinBase.cpp @@ -1292,90 +1292,7 @@ short CryGetAsyncKeyState(int vKey) return 0; } -#if defined(LINUX) || defined(APPLE) || defined(DEFINE_CRY_INTERLOCKED_INCREMENT) -//[K01]: http://www.memoryhole.net/kyle/2007/05/atomic_incrementing.html -//http://forums.devx.com/archive/index.php/t-160558.html -////////////////////////////////////////////////////////////////////////// -DLL_EXPORT LONG CryInterlockedIncrement(LONG volatile* lpAddend) -{ - /*int r; - __asm__ __volatile__ ( - "lock ; xaddl %0, (%1) \n\t" - : "=r" (r) - : "r" (lpAddend), "0" (1) - : "memory" - ); - return (LONG) (r + 1); */// add, since we get the original value back. - return __sync_fetch_and_add(lpAddend, 1) + 1; -} - -////////////////////////////////////////////////////////////////////////// -DLL_EXPORT LONG CryInterlockedDecrement(LONG volatile* lpAddend) -{ - /*int r; - __asm__ __volatile__ ( - "lock ; xaddl %0, (%1) \n\t" - : "=r" (r) - : "r" (lpAddend), "0" (-1) - : "memory" - ); - return (LONG) (r - 1); */// subtract, since we get the original value back. - return __sync_fetch_and_sub(lpAddend, 1) - 1; -} - -////////////////////////////////////////////////////////////////////////// -DLL_EXPORT LONG CryInterlockedExchangeAdd(LONG volatile* lpAddend, LONG Value) -{ - /* LONG r; - __asm__ __volatile__ ( - #if defined(LINUX64) || defined(APPLE) // long is 64 bits on amd64. - "lock ; xaddq %0, (%1) \n\t" - #else - "lock ; xaddl %0, (%1) \n\t" - #endif - : "=r" (r) - : "r" (lpAddend), "0" (Value) - : "memory" - ); - return r;*/ - return __sync_fetch_and_add(lpAddend, Value); -} - -DLL_EXPORT LONG CryInterlockedOr(LONG volatile* Destination, LONG Value) -{ - return __sync_fetch_and_or(Destination, Value); -} - -DLL_EXPORT LONG CryInterlockedCompareExchange(LONG volatile* dst, LONG exchange, LONG comperand) -{ - return __sync_val_compare_and_swap(dst, comperand, exchange); - /*LONG r; - __asm__ __volatile__ ( - #if defined(LINUX64) || defined(APPLE) // long is 64 bits on amd64. - "lock ; cmpxchgq %2, (%1) \n\t" - #else - "lock ; cmpxchgl %2, (%1) \n\t" - #endif - : "=a" (r) - : "r" (dst), "r" (exchange), "0" (comperand) - : "memory" - ); - return r;*/ -} - - -DLL_EXPORT void* CryInterlockedCompareExchangePointer(void* volatile* dst, void* exchange, void* comperand) -{ - return __sync_val_compare_and_swap(dst, comperand, exchange); - //return (void*)CryInterlockedCompareExchange((long volatile*)dst, (long)exchange, (long)comperand); -} - -DLL_EXPORT void* CryInterlockedExchangePointer(void* volatile* dst, void* exchange) -{ - __sync_synchronize(); - return __sync_lock_test_and_set(dst, exchange); - //return (void*)CryInterlockedCompareExchange((long volatile*)dst, (long)exchange, (long)comperand); -} +#if defined(LINUX) || defined(APPLE) threadID CryGetCurrentThreadId() { diff --git a/Code/Legacy/CryCommon/crycommon_files.cmake b/Code/Legacy/CryCommon/crycommon_files.cmake index d9d4493632..4c1440c67d 100644 --- a/Code/Legacy/CryCommon/crycommon_files.cmake +++ b/Code/Legacy/CryCommon/crycommon_files.cmake @@ -96,7 +96,6 @@ set(FILES LegacyAllocator.h MetaUtils.h MiniQueue.h - MultiThread.h MultiThread_Containers.h NullAudioSystem.h PNoise3.h diff --git a/Code/Legacy/CryCommon/platform.h b/Code/Legacy/CryCommon/platform.h index 9f6e8b212d..842325af9f 100644 --- a/Code/Legacy/CryCommon/platform.h +++ b/Code/Legacy/CryCommon/platform.h @@ -730,10 +730,6 @@ enum ETriState typedef int socklen_t; #endif - -// Include MultiThreading support. -#include "MultiThread.h" - // In RELEASE disable printf and fprintf #if defined(_RELEASE) && !defined(RELEASE_LOGGING) #if defined(AZ_RESTRICTED_PLATFORM) diff --git a/Code/Legacy/CryCommon/platform_impl.cpp b/Code/Legacy/CryCommon/platform_impl.cpp index e16b18bc06..becd88c0b5 100644 --- a/Code/Legacy/CryCommon/platform_impl.cpp +++ b/Code/Legacy/CryCommon/platform_impl.cpp @@ -308,58 +308,6 @@ short CryGetAsyncKeyState([[maybe_unused]] int vKey) #endif } -////////////////////////////////////////////////////////////////////////// -LONG CryInterlockedIncrement(int volatile* lpAddend) -{ - return InterlockedIncrement((volatile LONG*)lpAddend); -} - -////////////////////////////////////////////////////////////////////////// -LONG CryInterlockedDecrement(int volatile* lpAddend) -{ - return InterlockedDecrement((volatile LONG*)lpAddend); -} - -////////////////////////////////////////////////////////////////////////// -LONG CryInterlockedExchangeAdd(LONG volatile* lpAddend, LONG Value) -{ - return InterlockedExchangeAdd(lpAddend, Value); -} - -LONG CryInterlockedOr(LONG volatile* Destination, LONG Value) -{ - return InterlockedOr(Destination, Value); -} - -LONG CryInterlockedCompareExchange(LONG volatile* dst, LONG exchange, LONG comperand) -{ - return InterlockedCompareExchange(dst, exchange, comperand); -} - -void* CryInterlockedCompareExchangePointer(void* volatile* dst, void* exchange, void* comperand) -{ - return InterlockedCompareExchangePointer(dst, exchange, comperand); -} - -void* CryInterlockedExchangePointer(void* volatile* dst, void* exchange) -{ - return InterlockedExchangePointer(dst, exchange); -} - -void CryInterlockedAdd(volatile size_t* pVal, ptrdiff_t iAdd) -{ -#if defined (PLATFORM_64BIT) -#if !defined(NDEBUG) - size_t v = (size_t) -#endif - InterlockedAdd64((volatile int64*)pVal, iAdd); -#else - size_t v = (size_t)CryInterlockedExchangeAdd((volatile long*)pVal, (long)iAdd); - v += iAdd; -#endif - assert((iAdd == 0) || (iAdd < 0 && v < v - (size_t)iAdd) || (iAdd > 0 && v > v - (size_t)iAdd)); -} - ////////////////////////////////////////////////////////////////////////// uint32 CryGetFileAttributes(const char* lpFileName) { diff --git a/Code/Legacy/CrySystem/Log.h b/Code/Legacy/CrySystem/Log.h index 447186e613..085e05e714 100644 --- a/Code/Legacy/CrySystem/Log.h +++ b/Code/Legacy/CrySystem/Log.h @@ -10,7 +10,6 @@ #pragma once #include -#include #include ////////////////////////////////////////////////////////////////////// From 04e64e274f1b8cbd927fb3942cfcee55ecb14a7b Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Wed, 11 Aug 2021 16:53:41 -0700 Subject: [PATCH 30/70] Fix typo in copypasting... Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../AzCore/AzCore/UnitTest/Mocks/MockSettingsRegistry.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/UnitTest/Mocks/MockSettingsRegistry.h b/Code/Framework/AzCore/AzCore/UnitTest/Mocks/MockSettingsRegistry.h index a63e782146..7e6bb3d7b4 100644 --- a/Code/Framework/AzCore/AzCore/UnitTest/Mocks/MockSettingsRegistry.h +++ b/Code/Framework/AzCore/AzCore/UnitTest/Mocks/MockSettingsRegistry.h @@ -27,8 +27,8 @@ namespace AZ MOCK_METHOD1(RegisterNotifier, NotifyEventHandler(NotifyCallback&&)); MOCK_METHOD1(RegisterPreMergeEvent, PreMergeEventHandler(const PreMergeEventCallback&)); MOCK_METHOD1(RegisterPreMergeEvent, PreMergeEventHandler(PreMergeEventCallback&&)); - MOCK_METHOD1(PostMergeEventHandler, PreMergeEventHandler(const PostMergeEventCallback&)); - MOCK_METHOD1(PostMergeEventHandler, PreMergeEventHandler(PostMergeEventCallback&&)); + MOCK_METHOD1(RegisterPostMergeEvent, PostMergeEventHandler(const PostMergeEventCallback&)); + MOCK_METHOD1(RegisterPostMergeEvent, PostMergeEventHandler(PostMergeEventCallback&&)); MOCK_CONST_METHOD2(Get, bool(bool&, AZStd::string_view)); MOCK_CONST_METHOD2(Get, bool(s64&, AZStd::string_view)); From 8dd44075c85a98214dfa679e330de30cf6c5792f Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Wed, 11 Aug 2021 21:04:19 -0700 Subject: [PATCH 31/70] [redcode/crythread-2nd-pass] post merge include fixes Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Code/Editor/GameEngine.h | 1 - Code/Editor/Plugins/PerforcePlugin/PerforceSourceControl.cpp | 1 - .../Platform/Android/GridMate/Session/LANSession_Android.cpp | 1 + Code/Legacy/CryCommon/CryLibrary.h | 2 +- Code/Legacy/CryCommon/IFunctorBase.h | 2 -- Code/Legacy/CryCommon/IMaterial.h | 1 - Code/Legacy/CryCommon/smartptr.h | 1 - 7 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Code/Editor/GameEngine.h b/Code/Editor/GameEngine.h index 64fd20a9aa..4d183cc38e 100644 --- a/Code/Editor/GameEngine.h +++ b/Code/Editor/GameEngine.h @@ -20,7 +20,6 @@ #include "LogFile.h" #include "CryListenerSet.h" #include "Util/ModalWindowDismisser.h" -#include #endif class CStartupLogoDialog; diff --git a/Code/Editor/Plugins/PerforcePlugin/PerforceSourceControl.cpp b/Code/Editor/Plugins/PerforcePlugin/PerforceSourceControl.cpp index f8f4711631..34514b8ef1 100644 --- a/Code/Editor/Plugins/PerforcePlugin/PerforceSourceControl.cpp +++ b/Code/Editor/Plugins/PerforcePlugin/PerforceSourceControl.cpp @@ -9,7 +9,6 @@ #include "CryFile.h" #include "PerforceSourceControl.h" #include "PasswordDlg.h" -#include #include #include diff --git a/Code/Framework/GridMate/Platform/Android/GridMate/Session/LANSession_Android.cpp b/Code/Framework/GridMate/Platform/Android/GridMate/Session/LANSession_Android.cpp index 05fb56dfc1..3fa2a369a6 100644 --- a/Code/Framework/GridMate/Platform/Android/GridMate/Session/LANSession_Android.cpp +++ b/Code/Framework/GridMate/Platform/Android/GridMate/Session/LANSession_Android.cpp @@ -7,6 +7,7 @@ */ #include +#include namespace GridMate { diff --git a/Code/Legacy/CryCommon/CryLibrary.h b/Code/Legacy/CryCommon/CryLibrary.h index 787085af00..a034a2a04b 100644 --- a/Code/Legacy/CryCommon/CryLibrary.h +++ b/Code/Legacy/CryCommon/CryLibrary.h @@ -49,7 +49,7 @@ */ #include -#include +#include #include #define INJECT_ENVIRONMENT_FUNCTION "InjectEnvironment" diff --git a/Code/Legacy/CryCommon/IFunctorBase.h b/Code/Legacy/CryCommon/IFunctorBase.h index a64e811516..6fb3a5d981 100644 --- a/Code/Legacy/CryCommon/IFunctorBase.h +++ b/Code/Legacy/CryCommon/IFunctorBase.h @@ -14,8 +14,6 @@ #define CRYINCLUDE_CRYCOMMON_IFUNCTORBASE_H #pragma once -#include - #include // Base class for functor storage. diff --git a/Code/Legacy/CryCommon/IMaterial.h b/Code/Legacy/CryCommon/IMaterial.h index c484c10482..83f9140be7 100644 --- a/Code/Legacy/CryCommon/IMaterial.h +++ b/Code/Legacy/CryCommon/IMaterial.h @@ -37,7 +37,6 @@ struct IRenderMesh; #include #include #include -#include #ifdef MAX_SUB_MATERIALS // This checks that the values are in sync in the different files. diff --git a/Code/Legacy/CryCommon/smartptr.h b/Code/Legacy/CryCommon/smartptr.h index 0ff6a61b60..baf51d5030 100644 --- a/Code/Legacy/CryCommon/smartptr.h +++ b/Code/Legacy/CryCommon/smartptr.h @@ -13,7 +13,6 @@ #include #include -#include void CryFatalError(const char*, ...) PRINTF_PARAMS(1, 2); #if defined(APPLE) From 3fc0a197a0afa0206593aad40983e95f7917e13e Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Wed, 11 Aug 2021 21:32:02 -0700 Subject: [PATCH 32/70] [redcode/crythread-2nd-pass] removed re-implemented stubs of Windows synchapi.h functions and CrySimpleThread define in platform.h Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Code/Legacy/CryCommon/Linux_Win32Wrapper.h | 55 ----------- Code/Legacy/CryCommon/WinBase.cpp | 104 --------------------- Code/Legacy/CryCommon/platform.h | 10 +- 3 files changed, 1 insertion(+), 168 deletions(-) diff --git a/Code/Legacy/CryCommon/Linux_Win32Wrapper.h b/Code/Legacy/CryCommon/Linux_Win32Wrapper.h index 7b556b0f62..ffdf3fe998 100644 --- a/Code/Legacy/CryCommon/Linux_Win32Wrapper.h +++ b/Code/Legacy/CryCommon/Linux_Win32Wrapper.h @@ -413,67 +413,12 @@ inline void SetLastError(DWORD dwErrCode) { errno = dwErrCode; } ////////////////////////////////////////////////////////////////////////// extern threadID GetCurrentThreadId(); -////////////////////////////////////////////////////////////////////////// -extern HANDLE CreateEvent( - LPSECURITY_ATTRIBUTES lpEventAttributes, - BOOL bManualReset, - BOOL bInitialState, - LPCSTR lpName - ); - ////////////////////////////////////////////////////////////////////////// extern DWORD Sleep(DWORD dwMilliseconds); ////////////////////////////////////////////////////////////////////////// extern DWORD SleepEx(DWORD dwMilliseconds, BOOL bAlertable); -////////////////////////////////////////////////////////////////////////// -extern DWORD WaitForSingleObjectEx( - HANDLE hHandle, - DWORD dwMilliseconds, - BOOL bAlertable); - -////////////////////////////////////////////////////////////////////////// -extern DWORD WaitForMultipleObjectsEx( - DWORD nCount, - const HANDLE* lpHandles, - BOOL bWaitAll, - DWORD dwMilliseconds, - BOOL bAlertable); - -////////////////////////////////////////////////////////////////////////// -extern DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds); - -////////////////////////////////////////////////////////////////////////// -extern BOOL SetEvent(HANDLE hEvent); - -////////////////////////////////////////////////////////////////////////// -extern BOOL ResetEvent(HANDLE hEvent); - -////////////////////////////////////////////////////////////////////////// -extern HANDLE CreateMutex( - LPSECURITY_ATTRIBUTES lpMutexAttributes, - BOOL bInitialOwner, - LPCSTR lpName - ); - -////////////////////////////////////////////////////////////////////////// -extern BOOL ReleaseMutex(HANDLE hMutex); - -////////////////////////////////////////////////////////////////////////// -typedef DWORD (* PTHREAD_START_ROUTINE)(LPVOID lpThreadParameter); -typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; - -////////////////////////////////////////////////////////////////////////// -extern HANDLE CreateThread( - LPSECURITY_ATTRIBUTES lpThreadAttributes, - SIZE_T dwStackSize, - LPTHREAD_START_ROUTINE lpStartAddress, - LPVOID lpParameter, - DWORD dwCreationFlags, - LPDWORD lpThreadId - ); - extern BOOL GetComputerName(LPSTR lpBuffer, LPDWORD lpnSize); //required for CryOnline extern DWORD GetCurrentProcessId(void); diff --git a/Code/Legacy/CryCommon/WinBase.cpp b/Code/Legacy/CryCommon/WinBase.cpp index 732920f890..ae646e9e1c 100644 --- a/Code/Legacy/CryCommon/WinBase.cpp +++ b/Code/Legacy/CryCommon/WinBase.cpp @@ -923,21 +923,6 @@ threadID GetCurrentThreadId() } #endif -////////////////////////////////////////////////////////////////////////// -HANDLE CreateEvent -( - LPSECURITY_ATTRIBUTES lpEventAttributes, - BOOL bManualReset, - BOOL bInitialState, - LPCSTR lpName -) -{ - //TODO: implement - CRY_ASSERT_MESSAGE(0, "CreateEvent not implemented yet"); - return 0; -} - - ////////////////////////////////////////////////////////////////////////// DWORD Sleep(DWORD dwMilliseconds) { @@ -1003,95 +988,6 @@ DWORD SleepEx(DWORD dwMilliseconds, BOOL bAlertable) return 0; } -////////////////////////////////////////////////////////////////////////// -DWORD WaitForSingleObjectEx(HANDLE hHandle, DWORD dwMilliseconds, BOOL bAlertable) -{ - //TODO: implement - CRY_ASSERT_MESSAGE(0, "WaitForSingleObjectEx not implemented yet"); - return 0; -} - -#if 0 -////////////////////////////////////////////////////////////////////////// -DWORD WaitForMultipleObjectsEx( - DWORD nCount, - const HANDLE* lpHandles, - BOOL bWaitAll, - DWORD dwMilliseconds, - BOOL bAlertable) -{ - //TODO: implement - return 0; -} -#endif - -////////////////////////////////////////////////////////////////////////// -DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) -{ - //TODO: implement - CRY_ASSERT_MESSAGE(0, "WaitForSingleObject not implemented yet"); - return 0; -} - -////////////////////////////////////////////////////////////////////////// -BOOL SetEvent(HANDLE hEvent) -{ - //TODO: implement - CRY_ASSERT_MESSAGE(0, "SetEvent not implemented yet"); - return TRUE; -} - -////////////////////////////////////////////////////////////////////////// -BOOL ResetEvent(HANDLE hEvent) -{ - //TODO: implement - CRY_ASSERT_MESSAGE(0, "ResetEvent not implemented yet"); - return TRUE; -} - -////////////////////////////////////////////////////////////////////////// -HANDLE CreateMutex -( - LPSECURITY_ATTRIBUTES lpMutexAttributes, - BOOL bInitialOwner, - LPCSTR lpName -) -{ - //TODO: implement - CRY_ASSERT_MESSAGE(0, "CreateMutex not implemented yet"); - return 0; -} - -////////////////////////////////////////////////////////////////////////// -BOOL ReleaseMutex(HANDLE hMutex) -{ - //TODO: implement - CRY_ASSERT_MESSAGE(0, "ReleaseMutex not implemented yet"); - return TRUE; -} - -////////////////////////////////////////////////////////////////////////// - - -typedef DWORD (* PTHREAD_START_ROUTINE)(LPVOID lpThreadParameter); -typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; - -////////////////////////////////////////////////////////////////////////// -HANDLE CreateThread -( - LPSECURITY_ATTRIBUTES lpThreadAttributes, - SIZE_T dwStackSize, - LPTHREAD_START_ROUTINE lpStartAddress, - LPVOID lpParameter, - DWORD dwCreationFlags, - LPDWORD lpThreadId -) -{ - //TODO: implement - CRY_ASSERT_MESSAGE(0, "CreateThread not implemented yet"); - return 0; -} - #if defined(LINUX) || defined(APPLE) BOOL GetComputerName(LPSTR lpBuffer, LPDWORD lpnSize) { diff --git a/Code/Legacy/CryCommon/platform.h b/Code/Legacy/CryCommon/platform.h index 38c0ec7eb5..1b541a293e 100644 --- a/Code/Legacy/CryCommon/platform.h +++ b/Code/Legacy/CryCommon/platform.h @@ -142,14 +142,6 @@ #endif #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) #undef AZ_RESTRICTED_SECTION_IMPLEMENTED -#elif defined(LINUX) || defined(APPLE) - #if !defined(_DEBUG) - #define SIMPLE_THREAD_STACK_SIZE_KB (256) - #else - #define SIMPLE_THREAD_STACK_SIZE_KB (256 * 4) - #endif -#else - #define SIMPLE_THREAD_STACK_SIZE_KB (32) #endif #include @@ -198,7 +190,7 @@ #elif defined(ANDROID) #include "AndroidSpecific.h" #elif defined(IOS) - #include "iOSSpecific.h" + #include "iOSSpecific.h" #endif #endif From bbe6ff7b905e1d6b02fd2bfd00d2aa9252bc60d8 Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Thu, 12 Aug 2021 10:55:32 -0700 Subject: [PATCH 33/70] [redcode/crythread-2nd-pass] re-add LARGE_INTEGER definition to AppleSpecific.h Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Code/Legacy/CryCommon/AppleSpecific.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Code/Legacy/CryCommon/AppleSpecific.h b/Code/Legacy/CryCommon/AppleSpecific.h index c572250b26..ec7cd8306e 100644 --- a/Code/Legacy/CryCommon/AppleSpecific.h +++ b/Code/Legacy/CryCommon/AppleSpecific.h @@ -458,6 +458,21 @@ typedef HANDLE HMENU; #endif //__cplusplus +typedef union _LARGE_INTEGER +{ + struct + { + DWORD LowPart; + LONG HighPart; + }; + struct + { + DWORD LowPart; + LONG HighPart; + } u; + long long QuadPart; +} LARGE_INTEGER; + extern bool QueryPerformanceCounter(LARGE_INTEGER*); extern bool QueryPerformanceFrequency(LARGE_INTEGER* frequency); From 28c477997d9e97564424c6afbeccaa915b2bf8b1 Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Thu, 12 Aug 2021 10:58:41 -0700 Subject: [PATCH 34/70] [redcode/crythread-2nd-pass] fixed missing iOS include Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- .../GridMate/Platform/iOS/GridMate/Session/LANSession_iOS.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Code/Framework/GridMate/Platform/iOS/GridMate/Session/LANSession_iOS.cpp b/Code/Framework/GridMate/Platform/iOS/GridMate/Session/LANSession_iOS.cpp index 05fb56dfc1..3fa2a369a6 100644 --- a/Code/Framework/GridMate/Platform/iOS/GridMate/Session/LANSession_iOS.cpp +++ b/Code/Framework/GridMate/Platform/iOS/GridMate/Session/LANSession_iOS.cpp @@ -7,6 +7,7 @@ */ #include +#include namespace GridMate { From 72e99dd52b83272f0b57fd48015ead570cdb7dcb Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Thu, 12 Aug 2021 11:02:44 -0700 Subject: [PATCH 35/70] [redcode/crythread-2nd-pass] removed platform.h include hack linked to CryThread.h for apple platforms in ILog.h and ISystem.h Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Code/Legacy/CryCommon/ILog.h | 7 ------- Code/Legacy/CryCommon/ISystem.h | 7 ------- 2 files changed, 14 deletions(-) diff --git a/Code/Legacy/CryCommon/ILog.h b/Code/Legacy/CryCommon/ILog.h index e71e1f036d..23257ea59b 100644 --- a/Code/Legacy/CryCommon/ILog.h +++ b/Code/Legacy/CryCommon/ILog.h @@ -6,13 +6,6 @@ * */ - -// In Mac, including ILog without including platform.h first fails because platform.h -// includes CryThread.h which includes CryThread_pthreads.h which uses ILog. -// So plaform.h needs the contents of ILog.h. -// By including platform.h outside of the guard, we give platform.h the right include order -#include - #ifndef CRYINCLUDE_CRYCOMMON_ILOG_H #define CRYINCLUDE_CRYCOMMON_ILOG_H #pragma once diff --git a/Code/Legacy/CryCommon/ISystem.h b/Code/Legacy/CryCommon/ISystem.h index e0996fc927..ff72c2e60f 100644 --- a/Code/Legacy/CryCommon/ISystem.h +++ b/Code/Legacy/CryCommon/ISystem.h @@ -6,13 +6,6 @@ * */ - -// In Mac, including ISystem without including platform.h first fails because platform.h -// includes CryThread.h which includes CryThread_pthreads.h which uses ISystem (gEnv). -// So plaform.h needs the contents of ISystem.h. -// By including platform.h outside of the guard, we give platform.h the right include order -#include // Needed for LARGE_INTEGER (for consoles). - #ifndef CRYINCLUDE_CRYCOMMON_ISYSTEM_H #define CRYINCLUDE_CRYCOMMON_ISYSTEM_H #pragma once From cc3d2e9969cfc2f3ba00ebeaa9405d1d1886b37c Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Thu, 12 Aug 2021 12:40:03 -0700 Subject: [PATCH 36/70] [redcode/crythread-2nd-pass] replaced instances of AZStd::lock_guard<> with AZStd::scoped_lock as per feedback Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Code/Editor/CryEdit.cpp | 3 +-- Code/Editor/GameExporter.cpp | 2 +- Code/Editor/IEditorImpl.cpp | 6 +++--- .../PerforcePlugin/PerforceSourceControl.cpp | 2 +- Code/Legacy/CryCommon/CryAssert_Linux.h | 2 +- Code/Legacy/CrySystem/DebugCallStack.cpp | 6 +++--- Code/Legacy/CrySystem/Log.cpp | 8 ++++---- .../RemoteConsole/Core/RemoteConsoleCore.cpp | 17 +++++++++-------- 8 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp index 25a6313efe..8444f81317 100644 --- a/Code/Editor/CryEdit.cpp +++ b/Code/Editor/CryEdit.cpp @@ -938,10 +938,9 @@ void CCryEditApp::ShowSplashScreen(CCryEditApp* app) QObject::connect(splashScreen, &QObject::destroyed, splashScreen, [=] { - g_splashScreenStateLock.lock(); + AZStd::scoped_lock lock(g_splashScreenStateLock); g_pInitializeUIInfo = nullptr; g_splashScreen = nullptr; - g_splashScreenStateLock.unlock(); }); } diff --git a/Code/Editor/GameExporter.cpp b/Code/Editor/GameExporter.cpp index 3cd64f9fed..415103e10d 100644 --- a/Code/Editor/GameExporter.cpp +++ b/Code/Editor/GameExporter.cpp @@ -136,7 +136,7 @@ bool CGameExporter::Export(unsigned int flags, [[maybe_unused]] EEndian eExportE m_settings.SetHiQuality(); } - AZStd::lock_guard autoLock(CGameEngine::GetPakModifyMutex()); + AZStd::scoped_lock autoLock(CGameEngine::GetPakModifyMutex()); // Close this pak file. if (!CloseLevelPack(m_levelPak, true)) diff --git a/Code/Editor/IEditorImpl.cpp b/Code/Editor/IEditorImpl.cpp index 7800c7943e..1459139f66 100644 --- a/Code/Editor/IEditorImpl.cpp +++ b/Code/Editor/IEditorImpl.cpp @@ -252,7 +252,7 @@ void CEditorImpl::Uninitialize() void CEditorImpl::UnloadPlugins() { - AZStd::lock_guard lock(m_pluginMutex); + AZStd::scoped_lock lock(m_pluginMutex); // Flush core buses. We're about to unload DLLs and need to ensure we don't have module-owned functions left behind. AZ::Data::AssetBus::ExecuteQueuedEvents(); @@ -273,7 +273,7 @@ void CEditorImpl::UnloadPlugins() void CEditorImpl::LoadPlugins() { - AZStd::lock_guard lock(m_pluginMutex); + AZStd::scoped_lock lock(m_pluginMutex); static const QString editor_plugins_folder("EditorPlugins"); @@ -1460,7 +1460,7 @@ void CEditorImpl::UnregisterNotifyListener(IEditorNotifyListener* listener) ISourceControl* CEditorImpl::GetSourceControl() { - AZStd::lock_guard lock(m_pluginMutex); + AZStd::scoped_lock lock(m_pluginMutex); if (m_pSourceControl) { diff --git a/Code/Editor/Plugins/PerforcePlugin/PerforceSourceControl.cpp b/Code/Editor/Plugins/PerforcePlugin/PerforceSourceControl.cpp index 34514b8ef1..10c43c3d1b 100644 --- a/Code/Editor/Plugins/PerforcePlugin/PerforceSourceControl.cpp +++ b/Code/Editor/Plugins/PerforcePlugin/PerforceSourceControl.cpp @@ -56,7 +56,7 @@ void CPerforceSourceControl::ShowSettings() void CPerforceSourceControl::SetSourceControlState(SourceControlState state) { - AZStd::lock_guard lock(g_cPerforceValues); + AZStd::scoped_lock lock(g_cPerforceValues); switch (state) { diff --git a/Code/Legacy/CryCommon/CryAssert_Linux.h b/Code/Legacy/CryCommon/CryAssert_Linux.h index 355194caba..112c60a80c 100644 --- a/Code/Legacy/CryCommon/CryAssert_Linux.h +++ b/Code/Legacy/CryCommon/CryAssert_Linux.h @@ -80,7 +80,7 @@ bool CryAssert(const char* szCondition, const char* szFile, unsigned int line, b if (!gEnv->bNoAssertDialog && !gEnv->bIgnoreAllAsserts) { - AZStd::lock_guard lk (lock); + AZStd::scoped_lock lk(lock); snprintf(gs_command_str, max_len, "xterm -geometry 100x20 -n 'Assert Dialog [Linux Launcher]' -T 'Assert Dialog [Linux Launcher]' -e 'BinLinux/assert_term \"%s\" \"%s\" %d \"%s\"; echo \"$?\" > .assert_return'", szCondition, (file_len > 60) ? szFile + (file_len - 61) : szFile, line, gs_szMessage); int ret = system(gs_command_str); diff --git a/Code/Legacy/CrySystem/DebugCallStack.cpp b/Code/Legacy/CrySystem/DebugCallStack.cpp index 640afe8da1..cdfc5de21e 100644 --- a/Code/Legacy/CrySystem/DebugCallStack.cpp +++ b/Code/Legacy/CrySystem/DebugCallStack.cpp @@ -154,13 +154,13 @@ void DebugCallStack::SetUserDialogEnable(const bool bUserDialogEnable) DWORD g_idDebugThreads[10]; const char* g_nameDebugThreads[10]; int g_nDebugThreads = 0; -AZStd::spin_mutex g_lockThreadDumpList = 0; +AZStd::spin_mutex g_lockThreadDumpList; void MarkThisThreadForDebugging(const char* name) { EBUS_EVENT(AZ::Debug::EventTraceDrillerSetupBus, SetThreadName, AZStd::this_thread::get_id(), name); - AZStd::lock_guard lock(g_lockThreadDumpList); + AZStd::scoped_lock lock(g_lockThreadDumpList); DWORD id = GetCurrentThreadId(); if (g_nDebugThreads == sizeof(g_idDebugThreads) / sizeof(g_idDebugThreads[0])) { @@ -180,7 +180,7 @@ void MarkThisThreadForDebugging(const char* name) void UnmarkThisThreadFromDebugging() { - AZStd::lock_guard lock(g_lockThreadDumpList); + AZStd::scoped_lock lock(g_lockThreadDumpList); DWORD id = GetCurrentThreadId(); for (int i = g_nDebugThreads - 1; i >= 0; i--) { diff --git a/Code/Legacy/CrySystem/Log.cpp b/Code/Legacy/CrySystem/Log.cpp index 2417c58d4f..d248274b1d 100644 --- a/Code/Legacy/CrySystem/Log.cpp +++ b/Code/Legacy/CrySystem/Log.cpp @@ -810,13 +810,13 @@ void CLog::PushAssetScopeName(const char* sAssetType, const char* sName) SAssetScopeInfo as; as.sType = sAssetType; as.sName = sName; - AZStd::lock_guard scope_lock(m_assetScopeQueueLock); + AZStd::scoped_lock scope_lock(m_assetScopeQueueLock); m_assetScopeQueue.push_back(as); } void CLog::PopAssetScopeName() { - AZStd::lock_guard scope_lock(m_assetScopeQueueLock); + AZStd::scoped_lock scope_lock(m_assetScopeQueueLock); assert(!m_assetScopeQueue.empty()); if (!m_assetScopeQueue.empty()) { @@ -827,7 +827,7 @@ void CLog::PopAssetScopeName() ////////////////////////////////////////////////////////////////////////// const char* CLog::GetAssetScopeString() { - AZStd::lock_guard scope_lock(m_assetScopeQueueLock); + AZStd::scoped_lock scope_lock(m_assetScopeQueueLock); m_assetScopeString.clear(); for (size_t i = 0; i < m_assetScopeQueue.size(); i++) @@ -1450,7 +1450,7 @@ void CLog::Update() { if (!m_threadSafeMsgQueue.empty()) { - AZStd::lock_guard lock(m_threadSafeMsgQueue.get_lock()); // Get the lock and hold onto it until we clear the entire queue (prevents other threads adding more things in while we clear it) + AZStd::scoped_lock lock(m_threadSafeMsgQueue.get_lock()); // Get the lock and hold onto it until we clear the entire queue (prevents other threads adding more things in while we clear it) // Must be called from main thread SLogMsg msg; while (m_threadSafeMsgQueue.try_pop(msg)) diff --git a/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.cpp b/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.cpp index b59f697467..5a137d1664 100644 --- a/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.cpp +++ b/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.cpp @@ -133,19 +133,20 @@ void SRemoteServer::StopServer() AZ::AzSock::CloseSocket(m_socket); m_socket = SOCKET_ERROR; { - AZStd::lock_guard lock(m_mutex); + AZStd::scoped_lock lock(m_mutex); for (TClients::iterator it = m_clients.begin(); it != m_clients.end(); ++it) { it->pClient->StopClient(); } } AZStd::unique_lock lock(m_mutex); - m_stopCondition.wait(lock, [this] { return m_clients.empty(); });} + m_stopCondition.wait(lock, [this] { return m_clients.empty(); }); +} ///////////////////////////////////////////////////////////////////////////////////////////// void SRemoteServer::ClientDone(SRemoteClient* pClient) { - AZStd::lock_guard lock(m_mutex); + AZStd::scoped_lock lock(m_mutex); for (TClients::iterator it = m_clients.begin(); it != m_clients.end(); ++it) { if (it->pClient == pClient) @@ -253,7 +254,7 @@ void SRemoteServer::Run() continue; } - AZStd::lock_guard lock(m_mutex); + AZStd::scoped_lock lock(m_mutex); SRemoteClient* pClient = new SRemoteClient(this); m_clients.push_back(SRemoteClientInfo(pClient)); pClient->StartClient(sClient); @@ -266,7 +267,7 @@ void SRemoteServer::Run() ///////////////////////////////////////////////////////////////////////////////////////////// void SRemoteServer::AddEvent(IRemoteEvent* pEvent) { - AZStd::lock_guard lock(m_mutex); + AZStd::scoped_lock lock(m_mutex); for (TClients::iterator it = m_clients.begin(); it != m_clients.end(); ++it) { it->pEvents->push_back(pEvent->Clone()); @@ -277,7 +278,7 @@ void SRemoteServer::AddEvent(IRemoteEvent* pEvent) ///////////////////////////////////////////////////////////////////////////////////////////// void SRemoteServer::GetEvents(TEventBuffer& buffer) { - AZStd::lock_guard lock(m_mutex); + AZStd::scoped_lock lock(m_mutex); buffer = m_eventBuffer; m_eventBuffer.clear(); } @@ -287,7 +288,7 @@ bool SRemoteServer::WriteBuffer(SRemoteClient* pClient, char* buffer, int& size { IRemoteEvent* pEvent = nullptr; { - AZStd::lock_guard lock(m_mutex); + AZStd::scoped_lock lock(m_mutex); for (TClients::iterator it = m_clients.begin(); it != m_clients.end(); ++it) { if (it->pClient == pClient) @@ -330,7 +331,7 @@ bool SRemoteServer::ReadBuffer(const char* buffer, int data) { if (event->GetType() != eCET_Noop) { - AZStd::lock_guard lock(m_mutex); + AZStd::scoped_lock lock(m_mutex); m_eventBuffer.push_back(event); } else From c3ee798acc817aadc7b1bab8e51e67c3c31cfbf4 Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Thu, 12 Aug 2021 14:18:10 -0700 Subject: [PATCH 37/70] [redcode/crythread-2nd-pass] updated condition variable handling in Remote Console runtime to cut out extra unlock/lock Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Code/Tools/RemoteConsole/Core/RemoteConsoleCore.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.cpp b/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.cpp index 5a137d1664..a4e7bd24fa 100644 --- a/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.cpp +++ b/Code/Tools/RemoteConsole/Core/RemoteConsoleCore.cpp @@ -132,14 +132,12 @@ void SRemoteServer::StopServer() m_bAcceptClients = false; AZ::AzSock::CloseSocket(m_socket); m_socket = SOCKET_ERROR; - { - AZStd::scoped_lock lock(m_mutex); - for (TClients::iterator it = m_clients.begin(); it != m_clients.end(); ++it) - { - it->pClient->StopClient(); - } - } + AZStd::unique_lock lock(m_mutex); + for (TClients::iterator it = m_clients.begin(); it != m_clients.end(); ++it) + { + it->pClient->StopClient(); + } m_stopCondition.wait(lock, [this] { return m_clients.empty(); }); } From f0ff8da1d772a74c6c880c7a003ccf57f2c13473 Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Thu, 12 Aug 2021 16:51:54 -0700 Subject: [PATCH 38/70] [redcode/crythread-2nd-pass] post merge duplicates removed Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Code/LauncherUnified/Platform/Mac/Launcher_Mac.mm | 2 -- Code/Legacy/CryCommon/AppleSpecific.h | 15 --------------- 2 files changed, 17 deletions(-) diff --git a/Code/LauncherUnified/Platform/Mac/Launcher_Mac.mm b/Code/LauncherUnified/Platform/Mac/Launcher_Mac.mm index 3396200b87..cbd5a043e1 100644 --- a/Code/LauncherUnified/Platform/Mac/Launcher_Mac.mm +++ b/Code/LauncherUnified/Platform/Mac/Launcher_Mac.mm @@ -12,8 +12,6 @@ #include <../Common/UnixLike/Launcher_UnixLike.h> #include -#include - #if AZ_TESTS_ENABLED int main(int argc, char* argv[]) diff --git a/Code/Legacy/CryCommon/AppleSpecific.h b/Code/Legacy/CryCommon/AppleSpecific.h index 92fa318b87..cd3146403a 100644 --- a/Code/Legacy/CryCommon/AppleSpecific.h +++ b/Code/Legacy/CryCommon/AppleSpecific.h @@ -473,21 +473,6 @@ typedef HANDLE HMENU; #endif //__cplusplus -typedef union _LARGE_INTEGER -{ - struct - { - DWORD LowPart; - LONG HighPart; - }; - struct - { - DWORD LowPart; - LONG HighPart; - } u; - long long QuadPart; -} LARGE_INTEGER; - extern bool QueryPerformanceCounter(LARGE_INTEGER*); extern bool QueryPerformanceFrequency(LARGE_INTEGER* frequency); From 4cf384c2c555919e9e234c02c4d87fa0aef21840 Mon Sep 17 00:00:00 2001 From: moudgils <47460854+moudgils@users.noreply.github.com> Date: Thu, 12 Aug 2021 21:12:41 -0700 Subject: [PATCH 39/70] Fix minor typo (#3095) Signed-off-by: moudgils --- .../Platform/Mac/AzFramework/Windowing/NativeWindow_Mac.mm | 4 ++-- .../Platform/iOS/AzFramework/Windowing/NativeWindow_ios.mm | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Code/Framework/AzFramework/Platform/Mac/AzFramework/Windowing/NativeWindow_Mac.mm b/Code/Framework/AzFramework/Platform/Mac/AzFramework/Windowing/NativeWindow_Mac.mm index f9eef9170a..272faeb4c1 100644 --- a/Code/Framework/AzFramework/Platform/Mac/AzFramework/Windowing/NativeWindow_Mac.mm +++ b/Code/Framework/AzFramework/Platform/Mac/AzFramework/Windowing/NativeWindow_Mac.mm @@ -34,7 +34,7 @@ namespace AzFramework bool GetFullScreenState() const override; void SetFullScreenState(bool fullScreenState) override; bool CanToggleFullScreenState() const override { return true; } - uint32_t GetMainDisplayRefreshRate() const; + uint32_t GetDisplayRefreshRate() const override; private: static NSWindowStyleMask ConvertToNSWindowStyleMask(const WindowStyleMasks& styleMasks); @@ -142,7 +142,7 @@ namespace AzFramework return nativeMask ? nativeMask : defaultMask; } - uint32_t NativeWindowImpl_Darwin::GetMainDisplayRefreshRate() const + uint32_t NativeWindowImpl_Darwin::GetDisplayRefreshRate() const { return m_mainDisplayRefreshRate; } diff --git a/Code/Framework/AzFramework/Platform/iOS/AzFramework/Windowing/NativeWindow_ios.mm b/Code/Framework/AzFramework/Platform/iOS/AzFramework/Windowing/NativeWindow_ios.mm index 83e176b9ef..0486ca1b92 100644 --- a/Code/Framework/AzFramework/Platform/iOS/AzFramework/Windowing/NativeWindow_ios.mm +++ b/Code/Framework/AzFramework/Platform/iOS/AzFramework/Windowing/NativeWindow_ios.mm @@ -27,7 +27,7 @@ namespace AzFramework const WindowGeometry& geometry, const WindowStyleMasks& styleMasks) override; NativeWindowHandle GetWindowHandle() const override; - uint32_t GetMainDisplayRefreshRate() const; + uint32_t GetDisplayRefreshRate() const override; private: UIWindow* m_nativeWindow; @@ -66,7 +66,7 @@ namespace AzFramework return m_nativeWindow; } - uint32_t NativeWindowImpl_Ios::GetMainDisplayRefreshRate() const + uint32_t NativeWindowImpl_Ios::GetDisplayRefreshRate() const { return m_mainDisplayRefreshRate; } From 706333466e2137f11ba96105907f75291722d4c3 Mon Sep 17 00:00:00 2001 From: antonmic <56370189+antonmic@users.noreply.github.com> Date: Thu, 12 Aug 2021 23:58:51 -0700 Subject: [PATCH 40/70] Addressing PR feedback and making PassBuilder error if referenced shader isn't found Signed-off-by: antonmic <56370189+antonmic@users.noreply.github.com> --- .../Source/RPI.Builders/Pass/PassBuilder.cpp | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.cpp index a803ecf31a..f74792049f 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.cpp @@ -70,16 +70,16 @@ namespace AZ // Helper class to pass parameters to the AddDependency and FindReferencedAssets functions below struct FindPassReferenceAssetParams { - void* passAssetObject; + void* passAssetObject = nullptr; Uuid passAssetUuid; - SerializeContext* serializeContext; - AZStd::string_view passAssetSourceFile; // File path of the pass asset - AZStd::string_view dependencySourceFile; // File pass of the asset the pass asset depends on - const char* jobKey; // Job key for adding job dependency + SerializeContext* serializeContext = nullptr; + AZStd::string_view passAssetSourceFile; // File path of the pass asset + AZStd::string_view dependencySourceFile; // File pass of the asset the pass asset depends on + const char* jobKey = nullptr; // Job key for adding job dependency }; // Helper function to get a file reference and create a corresponding job dependency - void AddDependency(FindPassReferenceAssetParams& params, AssetBuilderSDK::JobDescriptor* job) + bool AddDependency(FindPassReferenceAssetParams& params, AssetBuilderSDK::JobDescriptor* job) { AZStd::string_view& file = params.dependencySourceFile; AZ::Data::AssetInfo sourceInfo; @@ -95,6 +95,12 @@ namespace AZ jobDependency.m_sourceFile.m_sourceFileDependencyPath = file; job->m_jobDependencyList.push_back(jobDependency); AZ_TracePrintf(PassBuilderName, "Creating job dependency on file [%s] \n", file.data()); + return true; + } + else + { + AZ_Error(PassBuilderName, false, "Could not find referenced file [%s]", file.data()); + return false; } } @@ -104,7 +110,7 @@ namespace AZ SerializeContext::ErrorHandler errorLogger; errorLogger.Reset(); - bool foundProblems = false; + bool success = true; // This callback will check whether the given element is an asset reference. If so, it will add it to the list of asset references auto beginCallback = [&](void* ptr, const SerializeContext::ClassData* classData, [[maybe_unused]] const SerializeContext::ClassElement* classElement) @@ -123,7 +129,8 @@ namespace AZ if (job != nullptr) // Create Job Phase { params.dependencySourceFile = path; - AddDependency(params, job); + bool dependencyAddedSuccessfully = AddDependency(params, job); + success = dependencyAddedSuccessfully && success; } else // Process Job Phase { @@ -136,7 +143,7 @@ namespace AZ else { AZ_Error(PassBuilderName, false, "Could not get AssetId for [%s]", assetReference->m_filePath.c_str()); - foundProblems = true; + success = false; } } } @@ -162,7 +169,7 @@ namespace AZ , nullptr ); - return !foundProblems; + return success; } // --- Code related to dependency shader asset handling --- From 4dd39c392979db451abbb22b1f4bae6220a7ed27 Mon Sep 17 00:00:00 2001 From: John Date: Fri, 13 Aug 2021 09:55:06 +0100 Subject: [PATCH 41/70] Address commit re-run corner case. Signed-off-by: John --- scripts/build/TestImpactAnalysis/tiaf.py | 47 ++++++---- .../tiaf_persistent_storage.py | 90 +++++++++++++++---- .../tiaf_persistent_storage_local.py | 13 ++- .../tiaf_persistent_storage_s3.py | 17 ++-- 4 files changed, 124 insertions(+), 43 deletions(-) diff --git a/scripts/build/TestImpactAnalysis/tiaf.py b/scripts/build/TestImpactAnalysis/tiaf.py index 6a43ad3c70..28de00d6ba 100644 --- a/scripts/build/TestImpactAnalysis/tiaf.py +++ b/scripts/build/TestImpactAnalysis/tiaf.py @@ -87,7 +87,7 @@ class TestImpact: try: # Attempt to generate a diff between the src and dst commits - logger.error(f"Source '{self._src_commit}' and destination '{self._dst_commit}' will be diff'd.") + logger.info(f"Source '{self._src_commit}' and destination '{self._dst_commit}' will be diff'd.") diff_path = pathlib.Path(pathlib.PurePath(self._temp_workspace).joinpath(f"changelist.{self._instance_id}.diff")) self._repo.create_diff_file(self._src_commit, self._dst_commit, diff_path, multi_branch) except RuntimeError as e: @@ -219,28 +219,37 @@ class TestImpact: try: # Persistent storage location if s3_bucket: - persistent_storage = PersistentStorageS3(self._config, suite, s3_bucket, s3_top_level_dir, self._source_of_truth_branch) + persistent_storage = PersistentStorageS3(self._config, suite, self._dst_commit, s3_bucket, s3_top_level_dir, self._source_of_truth_branch) else: - persistent_storage = PersistentStorageLocal(self._config, suite) + persistent_storage = PersistentStorageLocal(self._config, suite, self._dst_commit) except SystemError as e: logger.warning(f"The persistent storage encountered an irrecoverable error, test impact analysis will be disabled: '{e}'") persistent_storage = None if persistent_storage: - # Flag to signify whether or not this is a re-run (multiple runs of the same commit) - # Right now, we don't fully support re-runs but in the future we will have an extra subfolder for each commit hash with the - # last run hash that was used for the first run for the commit so we can retreive the same reference point for building the - # change list to ensure each subsequent run is using the same data but for the time being, just perform a regular run - is_rerun = False + + # Flag for corner case where: + # 1. TIAF was already run previously for this commit. + # 2. There was no last commit hash when TIAF last ran on this commit (due to no coverage data existing get for this branch) + # 3. TIAF has not been run on any other commits between the run for this commit and the last run for this commit. + # The above results in TIAF being stuck in a state of generating an empty change list (and thus doing no work until another + # commit comes in) which is problematic if the commit needs to be re-run for whatever reason so in these conditions we revert + # back to a regular test run until another commit comes in + cannot_rerun_with_instrumentation = False + if persistent_storage.has_historic_data: logger.info("Historic data found.") self._src_commit = persistent_storage.last_commit_hash - # Perform some basic sanity checks on the commit hashes to ensure confidence in the integrity of the environment - if self._src_commit == self._dst_commit: - logger.info(f"Source commit '{self._src_commit}' and destination commit '{self._dst_commit}', implying this is a re-run. A regular sequence will instead be performed.") - persistent_storage = None - is_rerun = True + # Check to see if this is a re-run for this commit before any other changes have come in + if persistent_storage.is_repeat_sequence: + if persistent_storage.can_rerun_sequence: + logger.info(f"This sequence is being re-run before any other changes have come in so the last commit '{persistent_storage.this_commit_last_commit_hash}' used for the previous sequence will be used instead.") + self._src_commit = persistent_storage.this_commit_last_commit_hash + else: + logger.info(f"This sequence is being re-run before any other changes have come in but there is no useful historic data. A regular sequence will be performed instead.") + persistent_storage = None + cannot_rerun_with_instrumentation = True else: self._attempt_to_generate_change_list() else: @@ -268,7 +277,7 @@ class TestImpact: args.append(f"--changelist={self._change_list_path}") logger.info(f"Change list is set to '{self._change_list_path}'.") else: - if self._is_source_of_truth_branch and not is_rerun: + if self._is_source_of_truth_branch and not cannot_rerun_with_instrumentation: # Use seed sequence (instrumented all tests) for coverage updating branches so we can generate the coverage bed for future sequences sequence_type = "seed" # We always continue after test failures when seeding to ensure we capture the coverage for all test targets @@ -314,14 +323,18 @@ class TestImpact: logger.info(f"Args: {unpacked_args}") runtime_result = subprocess.run([str(self._tiaf_bin)] + args) report = None - + # If the sequence completed (with or without failures) we will update the historical meta-data if runtime_result.returncode == 0 or runtime_result.returncode == 7: logger.info("Test impact analysis runtime returned successfully.") - if self._is_source_of_truth_branch and persistent_storage is not None: - persistent_storage.update_and_store_historic_data(self._dst_commit) + + # Get the sequence report the runtime generated with open(report_file) as json_file: report = json.load(json_file) + + # Attempt to store the historic data for this branch and sequence + if self._is_source_of_truth_branch and persistent_storage is not None: + persistent_storage.update_and_store_historic_data() else: logger.error(f"The test impact analysis runtime returned with error: '{runtime_result.returncode}'.") diff --git a/scripts/build/TestImpactAnalysis/tiaf_persistent_storage.py b/scripts/build/TestImpactAnalysis/tiaf_persistent_storage.py index 1ee3ac7e8c..3fff05b549 100644 --- a/scripts/build/TestImpactAnalysis/tiaf_persistent_storage.py +++ b/scripts/build/TestImpactAnalysis/tiaf_persistent_storage.py @@ -15,23 +15,39 @@ logger = get_logger(__file__) # Abstraction for the persistent storage required by TIAF to store and retrieve the branch coverage data and other meta-data class PersistentStorage(ABC): - def __init__(self, config: dict, suite: str): + + WORKSPACE_KEY = "workspace" + LAST_RUNS_KEY = "last_runs" + ACTIVE_KEY = "active" + ROOT_KEY = "root" + RELATIVE_PATHS_KEY = "relative_paths" + TEST_IMPACT_DATA_FILES_KEY = "test_impact_data_files" + LAST_COMMIT_HASH_KEY = "last_commit_hash" + COVERAGE_DATA_KEY = "coverage_data" + + def __init__(self, config: dict, suite: str, commit: str): """ Initializes the persistent storage into a state for which there is no historic data available. @param config: The runtime configuration to obtain the data file paths from. @param suite: The test suite for which the historic data will be obtained for. + @param commit: The commit hash for this build. """ # Work on the assumption that there is no historic meta-data (a valid state to be in, should none exist) self._last_commit_hash = None self._has_historic_data = False + self._has_previous_last_commit_hash = False + self._this_commit_hash = commit + self._this_commit_hash_last_commit_hash = None + self._historic_data = None + logger.info(f"Attempting to access persistent storage for the commit {self._this_commit_hash}") try: # The runtime expects the coverage data to be in the location specified in the config file (unless overridden with # the --datafile command line argument, which the TIAF scripts do not do) - self._active_workspace = pathlib.Path(config["workspace"]["active"]["root"]) - unpacked_coverage_data_file = config["workspace"]["active"]["relative_paths"]["test_impact_data_files"][suite] + self._active_workspace = pathlib.Path(config[self.WORKSPACE_KEY][self.ACTIVE_KEY][self.ROOT_KEY]) + unpacked_coverage_data_file = config[self.WORKSPACE_KEY][self.ACTIVE_KEY][self.RELATIVE_PATHS_KEY][self.TEST_IMPACT_DATA_FILES_KEY][suite] except KeyError as e: raise SystemError(f"The config does not contain the key {str(e)}.") @@ -45,17 +61,36 @@ class PersistentStorage(ABC): """ self._has_historic_data = False + self._has_previous_last_commit_hash = False try: - historic_data = json.loads(historic_data_json) - self._last_commit_hash = historic_data["last_commit_hash"] + self._historic_data = json.loads(historic_data_json) + + # Last commit hash for this branch + self._last_commit_hash = self._historic_data[self.LAST_COMMIT_HASH_KEY] logger.info(f"Last commit hash '{self._last_commit_hash}' found.") + if self.LAST_RUNS_KEY in self._historic_data: + # Last commit hash for the sequence that was run for this commit previously (if any) + if self._this_commit_hash in self._historic_data[self.LAST_RUNS_KEY]: + # 'None' is a valid value for the previously used last commit hash if there was no coverage data at that time + self._this_commit_hash_last_commit_hash = self._historic_data[self.LAST_RUNS_KEY][self._this_commit_hash] + self._has_previous_last_commit_hash = self._this_commit_hash_last_commit_hash is not None + + if self._has_previous_last_commit_hash: + logger.info(f"Last commit hash '{self._this_commit_hash_last_commit_hash}' was used previously for this commit.") + else: + logger.info(f"Prior sequence data found for this commit but it is empty (there was no coverage data vailable at that time).") + else: + logger.info(f"No prior sequence data found for commit '{self._this_commit_hash}', this is the first sequence for this commit.") + else: + logger.info(f"No prior sequence data found for any commits.") + # Create the active workspace directory where the coverage data file will be placed and unpack the coverage data so # it is accessible by the runtime self._active_workspace.mkdir(exist_ok=True) with open(self._unpacked_coverage_data_file, "w", newline='\n') as coverage_data: - coverage_data.write(historic_data["coverage_data"]) + coverage_data.write(self._historic_data[self.COVERAGE_DATA_KEY]) self._has_historic_data = True except json.JSONDecodeError: @@ -65,20 +100,31 @@ class PersistentStorage(ABC): except EnvironmentError as e: logger.error(f"There was a problem the coverage data file '{self._unpacked_coverage_data_file}': '{e}'.") - def _pack_historic_data(self, last_commit_hash: str): + def _pack_historic_data(self): """ Packs the current historic data into a JSON file for serializing. - @param last_commit_hash: The commit hash to associate the coverage data (and any other meta data) with. - @return: The packed historic data in JSON format. + @return: The packed historic data in JSON format. """ try: # Attempt to read the existing coverage data if self._unpacked_coverage_data_file.is_file(): + if not self._historic_data: + self._historic_data = {} + + # Last commit hash for this branch + self._historic_data[self.LAST_COMMIT_HASH_KEY] = self._this_commit_hash + + # Last commit hash for this commit + if not self.LAST_RUNS_KEY in self._historic_data: + self._historic_data[self.LAST_RUNS_KEY] = {} + self._historic_data[self.LAST_RUNS_KEY][self._this_commit_hash] = self._last_commit_hash + + # Coverage data for this branch with open(self._unpacked_coverage_data_file, "r") as coverage_data: - historic_data = {"last_commit_hash": last_commit_hash, "coverage_data": coverage_data.read()} - return json.dumps(historic_data) + self._historic_data[self.COVERAGE_DATA_KEY] = coverage_data.read() + return json.dumps(self._historic_data) else: logger.info(f"No coverage data exists at location '{self._unpacked_coverage_data_file}'.") except EnvironmentError as e: @@ -97,16 +143,14 @@ class PersistentStorage(ABC): """ pass - def update_and_store_historic_data(self, last_commit_hash: str): + def update_and_store_historic_data(self): """ Updates the historic data and stores it in the designated persistent storage location. - - @param last_commit_hash: The commit hash to associate the coverage data (and any other meta data) with. """ - historic_data_json = self._pack_historic_data(last_commit_hash) + historic_data_json = self._pack_historic_data() if historic_data_json: - logger.info(f"Attempting to store historic data with new last commit hash '{last_commit_hash}'...") + logger.info(f"Attempting to store historic data with new last commit hash '{self._this_commit_hash}'...") self._store_historic_data(historic_data_json) logger.info("The historic data was successfully stored.") @@ -119,4 +163,16 @@ class PersistentStorage(ABC): @property def last_commit_hash(self): - return self._last_commit_hash \ No newline at end of file + return self._last_commit_hash + + @property + def is_repeat_sequence(self): + return self._last_commit_hash == self._this_commit_hash + + @property + def this_commit_last_commit_hash(self): + return self._this_commit_hash_last_commit_hash + + @property + def can_rerun_sequence(self): + return self._has_previous_last_commit_hash \ No newline at end of file diff --git a/scripts/build/TestImpactAnalysis/tiaf_persistent_storage_local.py b/scripts/build/TestImpactAnalysis/tiaf_persistent_storage_local.py index ba9b58fbf3..c72fafc580 100644 --- a/scripts/build/TestImpactAnalysis/tiaf_persistent_storage_local.py +++ b/scripts/build/TestImpactAnalysis/tiaf_persistent_storage_local.py @@ -15,19 +15,24 @@ logger = get_logger(__file__) # Implementation of local persistent storage class PersistentStorageLocal(PersistentStorage): - def __init__(self, config: str, suite: str): + + HISTORIC_KEY = "historic" + DATA_KEY = "data" + + def __init__(self, config: str, suite: str, commit: str): """ Initializes the persistent storage with any local historic data available. @param config: The runtime config file to obtain the data file paths from. @param suite: The test suite for which the historic data will be obtained for. + @param commit: The commit hash for this build. """ - super().__init__(config, suite) + super().__init__(config, suite, commit) try: # Attempt to obtain the local persistent data location specified in the runtime config file - self._historic_workspace = pathlib.Path(config["workspace"]["historic"]["root"]) - historic_data_file = pathlib.Path(config["workspace"]["historic"]["relative_paths"]["data"]) + self._historic_workspace = pathlib.Path(config[self.WORKSPACE_KEY][self.HISTORIC_KEY][self.ROOT_KEY]) + historic_data_file = pathlib.Path(config[self.WORKSPACE_KEY][self.HISTORIC_KEY][self.RELATIVE_PATHS_KEY][self.DATA_KEY]) # Attempt to unpack the local historic data file self._historic_data_file = self._historic_workspace.joinpath(historic_data_file) diff --git a/scripts/build/TestImpactAnalysis/tiaf_persistent_storage_s3.py b/scripts/build/TestImpactAnalysis/tiaf_persistent_storage_s3.py index 1a279855ea..074caf73a1 100644 --- a/scripts/build/TestImpactAnalysis/tiaf_persistent_storage_s3.py +++ b/scripts/build/TestImpactAnalysis/tiaf_persistent_storage_s3.py @@ -18,16 +18,23 @@ logger = get_logger(__file__) # Implementation of s3 bucket persistent storage class PersistentStorageS3(PersistentStorage): - def __init__(self, config: dict, suite: str, s3_bucket: str, root_dir: str, branch: str): + + META_KEY = "meta" + BUILD_CONFIG_KEY = "build_config" + + def __init__(self, config: dict, suite: str, commit: str, s3_bucket: str, root_dir: str, branch: str): """ Initializes the persistent storage with the specified s3 bucket. @param config: The runtime config file to obtain the data file paths from. @param suite: The test suite for which the historic data will be obtained for. + @param commit: The commit hash for this build. @param s3_bucket: The s3 bucket to use for storing nd retrieving historic data. + @param root_dir: The root directory to use for the historic data object. + @branch branch: The branch to retrieve the historic data for. """ - super().__init__(config, suite) + super().__init__(config, suite, commit) try: # We store the historic data as compressed JSON @@ -37,8 +44,8 @@ class PersistentStorageS3(PersistentStorage): historic_data_file = f"historic_data.{object_extension}" # The location of the data is in the form // so the build config of each branch gets its own historic data - self._dir = f'{root_dir}/{branch}/{config["meta"]["build_config"]}' - self._historic_data_key = f'{self._dir}/{historic_data_file}' + self._historic_data_dir = f'{root_dir}/{branch}/{config[self.META_KEY][self.BUILD_CONFIG_KEY]}' + self._historic_data_key = f'{self._historic_data_dir}/{historic_data_file}' logger.info(f"Attempting to retrieve historic data for branch '{branch}' at location '{self._historic_data_key}' on bucket '{s3_bucket}'...") self._s3 = boto3.resource("s3") @@ -49,7 +56,7 @@ class PersistentStorageS3(PersistentStorage): logger.info(f"Historic data found for branch '{branch}'.") # Archive the existing object with the name of the existing last commit hash - #archive_key = f"{self._dir}/archive/{self._last_commit_hash}.{object_extension}" + #archive_key = f"{self._historic_data_dir}/archive/{self._last_commit_hash}.{object_extension}" #logger.info(f"Archiving existing historic data to '{archive_key}' in bucket '{self._bucket.name}'...") #self._bucket.copy({"Bucket": self._bucket.name, "Key": self._historic_data_key}, archive_key) #logger.info(f"Archiving complete.") From a1d855a920f2f741a2aff48b4251b84628598e78 Mon Sep 17 00:00:00 2001 From: John Date: Fri, 13 Aug 2021 10:03:09 +0100 Subject: [PATCH 42/70] Invert corner case flag for readability. Signed-off-by: John --- scripts/build/TestImpactAnalysis/tiaf.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/build/TestImpactAnalysis/tiaf.py b/scripts/build/TestImpactAnalysis/tiaf.py index 28de00d6ba..e8faef30e3 100644 --- a/scripts/build/TestImpactAnalysis/tiaf.py +++ b/scripts/build/TestImpactAnalysis/tiaf.py @@ -235,7 +235,7 @@ class TestImpact: # The above results in TIAF being stuck in a state of generating an empty change list (and thus doing no work until another # commit comes in) which is problematic if the commit needs to be re-run for whatever reason so in these conditions we revert # back to a regular test run until another commit comes in - cannot_rerun_with_instrumentation = False + can_rerun_with_instrumentation = True if persistent_storage.has_historic_data: logger.info("Historic data found.") @@ -249,7 +249,7 @@ class TestImpact: else: logger.info(f"This sequence is being re-run before any other changes have come in but there is no useful historic data. A regular sequence will be performed instead.") persistent_storage = None - cannot_rerun_with_instrumentation = True + can_rerun_with_instrumentation = False else: self._attempt_to_generate_change_list() else: @@ -277,7 +277,7 @@ class TestImpact: args.append(f"--changelist={self._change_list_path}") logger.info(f"Change list is set to '{self._change_list_path}'.") else: - if self._is_source_of_truth_branch and not cannot_rerun_with_instrumentation: + if self._is_source_of_truth_branch and can_rerun_with_instrumentation: # Use seed sequence (instrumented all tests) for coverage updating branches so we can generate the coverage bed for future sequences sequence_type = "seed" # We always continue after test failures when seeding to ensure we capture the coverage for all test targets From 99b369198bb9a8b1e62e870b075031033a69b63e Mon Sep 17 00:00:00 2001 From: Kevin Y <88146293+kev197@users.noreply.github.com> Date: Fri, 13 Aug 2021 08:59:38 -0400 Subject: [PATCH 43/70] Typo fix in duplicate project progress window (#2969) Signed-off-by: Kevin Yu --- Code/Tools/ProjectManager/Source/ProjectUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.cpp b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp index 52900f1b28..fb0ea23ece 100644 --- a/Code/Tools/ProjectManager/Source/ProjectUtils.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp @@ -189,7 +189,7 @@ namespace O3DE::ProjectManager const QString copiedFileSizeString = locale.formattedDataSize(outCopiedFileSize); const QString totalFileSizeString = locale.formattedDataSize(totalSizeToCopy); - progressDialog->setLabelText(QString("Coping file %1 of %2 (%3 of %4) ...").arg(QString::number(outNumCopiedFiles), + progressDialog->setLabelText(QString("Copying file %1 of %2 (%3 of %4) ...").arg(QString::number(outNumCopiedFiles), QString::number(filesToCopyCount), copiedFileSizeString, totalFileSizeString)); From a55cb3e35fa4ac69f6082a101ac7faab66c75a27 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Fri, 13 Aug 2021 09:09:55 -0700 Subject: [PATCH 44/70] Fixed white-bar at bottom of Project Manager screen (#3091) Signed-off-by: AMZN-alexpete <26804013+AMZN-alexpete@users.noreply.github.com> --- Code/Tools/ProjectManager/Source/Application.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Code/Tools/ProjectManager/Source/Application.cpp b/Code/Tools/ProjectManager/Source/Application.cpp index c977698152..9ca107dae5 100644 --- a/Code/Tools/ProjectManager/Source/Application.cpp +++ b/Code/Tools/ProjectManager/Source/Application.cpp @@ -168,9 +168,13 @@ namespace O3DE::ProjectManager // the decoration wrapper is intended to remember window positioning and sizing auto wrapper = new AzQtComponents::WindowDecorationWrapper(); wrapper->setGuest(m_mainWindow.data()); + + // show the main window here to apply the stylesheet before restoring geometry or we + // can end up with empty white space at the bottom of the window until the frame is resized again + m_mainWindow->show(); + wrapper->enableSaveRestoreGeometry("O3DE", "ProjectManager", "mainWindowGeometry"); wrapper->showFromSettings(); - m_mainWindow->show(); qApp->setQuitOnLastWindowClosed(true); From 716089e803645f5b08f2b847d5e8c83d75a831e2 Mon Sep 17 00:00:00 2001 From: kberg-amzn Date: Fri, 13 Aug 2021 09:57:40 -0700 Subject: [PATCH 45/70] More fixes and some temp debugging logs Signed-off-by: kberg-amzn --- .../LocalPredictionPlayerInputComponent.cpp | 59 +++++++------------ .../Source/Components/NetBindComponent.cpp | 6 +- 2 files changed, 25 insertions(+), 40 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp index ca970de37b..72f5aa8e1c 100644 --- a/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/LocalPredictionPlayerInputComponent.cpp @@ -66,6 +66,11 @@ namespace Multiplayer } } + inline double ConvertTimeMsToSeconds(AZ::TimeMs value) + { + return static_cast(static_cast(value)) / 1000.0; + } + void LocalPredictionPlayerInputComponent::LocalPredictionPlayerInputComponent::Reflect(AZ::ReflectContext* context) { AZ::SerializeContext* serializeContext = azrtti_cast(context); @@ -151,7 +156,7 @@ namespace Multiplayer } const AZ::TimeMs currentTimeMs = AZ::GetElapsedTimeMs(); - const double clientInputRateSec = static_cast(static_cast(cl_InputRateMs)) / 1000.0; + const double clientInputRateSec = ConvertTimeMsToSeconds(cl_InputRateMs); m_lastInputReceivedTimeMs = currentTimeMs; // Keep track of last inputs received, also allows us to update frame ids @@ -176,8 +181,8 @@ namespace Multiplayer if (m_clientBankedTime < sv_MaxBankTimeWindowSec) { // Client blends from previous frame to target so here we subtract blend factor to get to that state - const float blendFactor = AZStd::min(AZStd::max(0.f, input.GetHostBlendFactor()), 1.f); - const AZ::TimeMs blendMs = AZ::TimeMs(static_cast(static_cast(cl_InputRateMs)) * (1.f - blendFactor)); + const float blendFactor = AZStd::min(AZStd::max(0.f, input.GetHostBlendFactor()), 1.0f); + const AZ::TimeMs blendMs = AZ::TimeMs(static_cast(static_cast(cl_InputRateMs)) * (1.0f - blendFactor)); m_clientBankedTime = AZStd::min(m_clientBankedTime + clientInputRateSec, (double)sv_MaxBankTimeWindowSec); // clamp to boundary { ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs() - blendMs, input.GetHostBlendFactor(), invokingConnection->GetConnectionId()); @@ -259,7 +264,7 @@ namespace Multiplayer return; } - const float clientInputRateSec = static_cast(static_cast(cl_InputRateMs)) / 1000.0; + const double clientInputRateSec = ConvertTimeMsToSeconds(cl_InputRateMs); // Copy array so we can modify input ids NetworkInputMigrationVector inputArrayCopy = inputArray; @@ -334,7 +339,7 @@ namespace Multiplayer // If this correction is for a move outside our input history window, just start replaying from the oldest move we have available const uint32_t startReplayIndex = (inputHistorySize > historicalDelta) ? (inputHistorySize - historicalDelta) : 0; - const float clientInputRateSec = static_cast(static_cast(cl_InputRateMs)) / 1000.0; + const double clientInputRateSec = ConvertTimeMsToSeconds(cl_InputRateMs); for (uint32_t replayIndex = startReplayIndex; replayIndex < inputHistorySize; ++replayIndex) { // Reprocess the input for this frame @@ -405,9 +410,9 @@ namespace Multiplayer void LocalPredictionPlayerInputComponentController::UpdateAutonomous(AZ::TimeMs deltaTimeMs) { - const double deltaTime = static_cast(deltaTimeMs) / 1000.0; - const double inputRate = static_cast(static_cast(cl_InputRateMs)) / 1000.0; - const double maxRewindHistory = static_cast(static_cast(cl_MaxRewindHistoryMs)) / 1000.0; + const double deltaTime = ConvertTimeMsToSeconds(deltaTimeMs); + const double clientInputRateSec = ConvertTimeMsToSeconds(cl_InputRateMs); + const double maxRewindHistory = ConvertTimeMsToSeconds(cl_MaxRewindHistoryMs); #ifndef AZ_RELEASE_BUILD m_moveAccumulator += deltaTime * cl_DebugHackTimeMultiplier; @@ -415,13 +420,13 @@ namespace Multiplayer m_moveAccumulator += deltaTime; #endif - const uint32_t maxClientInputs = inputRate > 0.0 ? static_cast(maxRewindHistory / inputRate) : 0; + const uint32_t maxClientInputs = clientInputRateSec > 0.0 ? static_cast(maxRewindHistory / clientInputRateSec) : 0; IMultiplayer* multiplayer = GetMultiplayer(); INetworkTime* networkTime = GetNetworkTime(); - while (m_moveAccumulator >= inputRate) + while (m_moveAccumulator >= clientInputRateSec) { - m_moveAccumulator -= inputRate; + m_moveAccumulator -= clientInputRateSec; ++m_clientInputId; NetworkInputArray inputArray(GetEntityHandle()); @@ -433,10 +438,10 @@ namespace Multiplayer input.SetHostBlendFactor(multiplayer->GetCurrentBlendFactor()); // Allow components to form the input for this frame - GetNetBindComponent()->CreateInput(input, inputRate); + GetNetBindComponent()->CreateInput(input, clientInputRateSec); // Process the input for this frame - GetNetBindComponent()->ProcessInput(input, inputRate); + GetNetBindComponent()->ProcessInput(input, clientInputRateSec); AZLOG(NET_Prediction, "Processed InputId=%d", aznumeric_cast(m_clientInputId)); @@ -444,28 +449,6 @@ namespace Multiplayer AzNetworking::HashSerializer hashSerializer; GetNetBindComponent()->SerializeEntityCorrection(hashSerializer); - // In debug, send the entire client output state to the server to make it easier to debug desync issues - AzNetworking::PacketEncodingBuffer processInputResult; -#ifndef AZ_RELEASE_BUILD - if (cl_EnableDesyncDebugging) - { - AzNetworking::NetworkInputSerializer processInputResultSerializer(processInputResult.GetBuffer(), processInputResult.GetCapacity()); - GetNetBindComponent()->SerializeEntityCorrection(processInputResultSerializer); - processInputResult.Resize(processInputResultSerializer.GetSize()); - } -#endif - - // In debug, send the entire client output state to the server to make it easier to debug desync issues - AzNetworking::PacketEncodingBuffer processInputResult; -#ifndef AZ_RELEASE_BUILD - if (cl_EnableDesyncDebugging) - { - AzNetworking::NetworkInputSerializer processInputResultSerializer(processInputResult.GetBuffer(), static_cast(processInputResult.GetCapacity())); - GetNetBindComponent()->SerializeEntityCorrection(processInputResultSerializer); - processInputResult.Resize(processInputResultSerializer.GetSize()); - } -#endif - // Save this input and discard move history outside our client rewind window m_inputHistory.PushBack(input); while (m_inputHistory.Size() > maxClientInputs) @@ -508,7 +491,7 @@ namespace Multiplayer void LocalPredictionPlayerInputComponentController::UpdateBankedTime(AZ::TimeMs deltaTimeMs) { const double deltaTime = static_cast(deltaTimeMs) / 1000.0; - const double inputRate = static_cast(static_cast(cl_InputRateMs)) / 1000.0; + const double clientInputRateSec = static_cast(static_cast(cl_InputRateMs)) / 1000.0; const double maxRewindHistory = static_cast(static_cast(cl_MaxRewindHistoryMs)) / 1000.0; // Update banked time accumulator @@ -522,8 +505,8 @@ namespace Multiplayer NetworkInput& input = m_lastInputReceived[0]; { - ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), DefaultBlendFactor, AzNetworking::InvalidConnectionId); - GetNetBindComponent()->ProcessInput(input, inputRate); + ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), DefaultBlendFactor, GetNetBindComponent()->GetOwningConnectionId()); + GetNetBindComponent()->ProcessInput(input, clientInputRateSec); } AZLOG(NET_Prediction, "Forced InputId=%d", aznumeric_cast(input.GetClientInputId())); diff --git a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp index 070655e768..ef1bf8c8e8 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp @@ -274,8 +274,8 @@ namespace Multiplayer void NetBindComponent::CreateInput(NetworkInput& networkInput, float deltaTime) { - // Only autonomous or authority runs this logic - AZ_Assert(m_netEntityRole == NetEntityRole::Autonomous || m_netEntityRole == NetEntityRole::Authority, "Incorrect network role for input creation"); + // Only autonomous runs this logic + AZ_Assert(IsNetEntityRoleAutonomous(), "Incorrect network role for input creation"); for (MultiplayerComponent* multiplayerComponent : m_multiplayerInputComponentVector) { multiplayerComponent->GetController()->CreateInput(networkInput, deltaTime); @@ -284,6 +284,8 @@ namespace Multiplayer void NetBindComponent::ProcessInput(NetworkInput& networkInput, float deltaTime) { + AZ_TracePrintf("gathers", "Processing input, inputId=%d", static_cast(networkInput.GetClientInputId())); + m_isProcessingInput = true; // Only autonomous and authority runs this logic AZ_Assert((NetworkRoleHasController(m_netEntityRole)), "Incorrect network role for input processing"); From 9571a15769fc88c2713ca5ea6b834523b525c08e Mon Sep 17 00:00:00 2001 From: mrieggeramzn <61609885+mrieggeramzn@users.noreply.github.com> Date: Fri, 13 Aug 2021 11:36:58 -0700 Subject: [PATCH 46/70] Atom/mriegger/explicit set pcf address mode (#3061) * Explicit setting the addressing mode for the pcf shadowing * Explicitly setting addressing mode for sampler --- .../Assets/ShaderResourceGroups/CoreLights/SceneSrg.azsli | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/SceneSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/SceneSrg.azsli index d1a916dfac..67ccedd720 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/SceneSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/SceneSrg.azsli @@ -30,6 +30,9 @@ partial ShaderResourceGroup SceneSrg // Hardware PCF comparison sampler that is used when sampling the shadow maps SamplerComparisonState m_hwPcfSampler { + AddressU = Clamp; + AddressV = Clamp; + AddressW = Clamp; MagFilter = Linear; MinFilter = Linear; MipFilter = Point; From cd5081a7c3006d72b88dc196ffac0b3a66049673 Mon Sep 17 00:00:00 2001 From: michabr <82236305+michabr@users.noreply.github.com> Date: Fri, 13 Aug 2021 13:31:46 -0700 Subject: [PATCH 47/70] Fix byte alignment issue for index/vertex buffers (#3110) * Fix byte alignment issue for index/vertex buffers * Remove default alignment value when getting dynamic buffer Signed-off-by: abrmich --- .../Code/Source/AuxGeom/DynamicPrimitiveProcessor.cpp | 4 ++-- .../Include/Atom/RPI.Public/DynamicDraw/DynamicBuffer.h | 4 ++-- .../Atom/RPI.Public/DynamicDraw/DynamicDrawInterface.h | 2 +- .../Include/Atom/RPI.Public/DynamicDraw/DynamicDrawSystem.h | 2 +- .../Source/RPI.Public/DynamicDraw/DynamicDrawContext.cpp | 6 +++--- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/DynamicPrimitiveProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/DynamicPrimitiveProcessor.cpp index 3a7d50d2a9..10d1bdc2c6 100644 --- a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/DynamicPrimitiveProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/DynamicPrimitiveProcessor.cpp @@ -196,7 +196,7 @@ namespace AZ { const size_t sourceByteSize = source.size() * sizeof(AuxGeomIndex); - RHI::Ptr dynamicBuffer = RPI::DynamicDrawInterface::Get()->GetDynamicBuffer(static_cast(sourceByteSize)); + RHI::Ptr dynamicBuffer = RPI::DynamicDrawInterface::Get()->GetDynamicBuffer(static_cast(sourceByteSize), RHI::Alignment::InputAssembly); if (!dynamicBuffer) { AZ_WarningOnce("AuxGeom", false, "Failed to allocate dynamic buffer of size %d.", sourceByteSize); @@ -211,7 +211,7 @@ namespace AZ { const size_t sourceByteSize = source.size() * sizeof(AuxGeomDynamicVertex); - RHI::Ptr dynamicBuffer = RPI::DynamicDrawInterface::Get()->GetDynamicBuffer(static_cast(sourceByteSize)); + RHI::Ptr dynamicBuffer = RPI::DynamicDrawInterface::Get()->GetDynamicBuffer(static_cast(sourceByteSize), RHI::Alignment::InputAssembly); if (!dynamicBuffer) { AZ_WarningOnce("AuxGeom", false, "Failed to allocate dynamic buffer of size %d.", sourceByteSize); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/DynamicDraw/DynamicBuffer.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/DynamicDraw/DynamicBuffer.h index 0c13efbd4b..c50ba2dc9b 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/DynamicDraw/DynamicBuffer.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/DynamicDraw/DynamicBuffer.h @@ -25,8 +25,8 @@ namespace AZ //! DynamicBuffers are allocated by DynamicBufferAllocator. Check the description of DynamicBufferAllocator class for detail. //! The typical usage: //! // For every frame - //! auto buffer = DynamicDrawInterface::Get()->GetDynamicBuffer(size); - //! if (buffer) // the buffer could be empty if the allocation failed.e + //! auto buffer = DynamicDrawInterface::Get()->GetDynamicBuffer(size, RHI::Alignment::InputAssembly); + //! if (buffer) // the buffer could be empty if the allocation failed. //! { //! // write data to the buffer //! buffer->Write(data, size); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/DynamicDraw/DynamicDrawInterface.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/DynamicDraw/DynamicDrawInterface.h index cc2125af95..23a93481fd 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/DynamicDraw/DynamicDrawInterface.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/DynamicDraw/DynamicDrawInterface.h @@ -54,7 +54,7 @@ namespace AZ //! Get a DynamicBuffer from DynamicDrawSystem. //! The returned buffer will be invalidated every time the RPISystem's RenderTick is called - virtual RHI::Ptr GetDynamicBuffer(uint32_t size, uint32_t alignment = 1) = 0; + virtual RHI::Ptr GetDynamicBuffer(uint32_t size, uint32_t alignment) = 0; //! Draw a geometry to a scene with a given material virtual void DrawGeometry(Data::Instance material, const GeometryData& geometry, ScenePtr scene) = 0; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/DynamicDraw/DynamicDrawSystem.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/DynamicDraw/DynamicDrawSystem.h index 4210bca1db..4a00566632 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/DynamicDraw/DynamicDrawSystem.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/DynamicDraw/DynamicDrawSystem.h @@ -32,7 +32,7 @@ namespace AZ // DynamicDrawInterface overrides... RHI::Ptr CreateDynamicDrawContext() override; - RHI::Ptr GetDynamicBuffer(uint32_t size, uint32_t alignment = 1) override; + RHI::Ptr GetDynamicBuffer(uint32_t size, uint32_t alignment) override; void DrawGeometry(Data::Instance material, const GeometryData& geometry, ScenePtr scene) override; void AddDrawPacket(Scene* scene, AZStd::unique_ptr drawPacket) override; AZStd::vector GetDrawListsForPass(const RasterPass* pass) override; 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 7ca2bdcee5..29f57d6e0f 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/DynamicDraw/DynamicDrawContext.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/DynamicDraw/DynamicDrawContext.cpp @@ -474,10 +474,10 @@ namespace AZ // Get dynamic buffers for vertex and index buffer. Skip draw if failed to allocate buffers uint32_t vertexDataSize = vertexCount * m_perVertexDataSize; RHI::Ptr vertexBuffer; - vertexBuffer = DynamicDrawInterface::Get()->GetDynamicBuffer(vertexDataSize); + vertexBuffer = DynamicDrawInterface::Get()->GetDynamicBuffer(vertexDataSize, RHI::Alignment::InputAssembly); uint32_t indexDataSize = indexCount * RHI::GetIndexFormatSize(indexFormat); - RHI::Ptr indexBuffer = DynamicDrawInterface::Get()->GetDynamicBuffer(indexDataSize); + RHI::Ptr indexBuffer = DynamicDrawInterface::Get()->GetDynamicBuffer(indexDataSize, RHI::Alignment::InputAssembly); if (indexBuffer == nullptr || vertexBuffer == nullptr) { @@ -572,7 +572,7 @@ namespace AZ // Get dynamic buffers for vertex and index buffer. Skip draw if failed to allocate buffers uint32_t vertexDataSize = vertexCount * m_perVertexDataSize; RHI::Ptr vertexBuffer; - vertexBuffer = DynamicDrawInterface::Get()->GetDynamicBuffer(vertexDataSize); + vertexBuffer = DynamicDrawInterface::Get()->GetDynamicBuffer(vertexDataSize, RHI::Alignment::InputAssembly); if (vertexBuffer == nullptr) { From 80aa4c42ce8082de578c8d3a78b1a95908aeea08 Mon Sep 17 00:00:00 2001 From: evanchia-ly-sdets <80914607+evanchia-ly-sdets@users.noreply.github.com> Date: Fri, 13 Aug 2021 13:41:56 -0700 Subject: [PATCH 48/70] moving smoke test to sandbox suite to investigate failures (#3109) Signed-off-by: evanchia --- .../Gem/PythonTests/smoke/CMakeLists.txt | 12 ++++++++++++ .../smoke/test_RemoteConsole_CPULoadLevel_Works.py | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/AutomatedTesting/Gem/PythonTests/smoke/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/smoke/CMakeLists.txt index 3fc4f3db0e..5374b0d318 100644 --- a/AutomatedTesting/Gem/PythonTests/smoke/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/smoke/CMakeLists.txt @@ -73,5 +73,17 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) AutomatedTesting.GameLauncher AutomatedTesting.Assets ) + ly_add_pytest( + NAME AutomatedTesting::LoadLevelCPU + TEST_SUITE sandbox + PATH ${CMAKE_CURRENT_LIST_DIR}/test_RemoteConsole_CPULoadLevel_Works.py + TIMEOUT 100 + RUNTIME_DEPENDENCIES + AZ::AssetProcessor + AZ::PythonBindingsExample + Legacy::Editor + AutomatedTesting.GameLauncher + AutomatedTesting.Assets + ) endif() diff --git a/AutomatedTesting/Gem/PythonTests/smoke/test_RemoteConsole_CPULoadLevel_Works.py b/AutomatedTesting/Gem/PythonTests/smoke/test_RemoteConsole_CPULoadLevel_Works.py index 6522514f2f..701dcfab10 100644 --- a/AutomatedTesting/Gem/PythonTests/smoke/test_RemoteConsole_CPULoadLevel_Works.py +++ b/AutomatedTesting/Gem/PythonTests/smoke/test_RemoteConsole_CPULoadLevel_Works.py @@ -24,7 +24,7 @@ from ly_remote_console.remote_console_commands import ( @pytest.mark.parametrize("launcher_platform", ["windows"]) @pytest.mark.parametrize("project", ["AutomatedTesting"]) @pytest.mark.parametrize("level", ["Simple"]) -@pytest.mark.SUITE_smoke +@pytest.mark.SUITE_sandbox class TestRemoteConsoleLoadLevelWorks(object): @pytest.fixture def remote_console_instance(self, request): From 63a78b906ad04e3fc19d0dfb570f5e7173303e11 Mon Sep 17 00:00:00 2001 From: jromnoa <80134229+jromnoa@users.noreply.github.com> Date: Fri, 13 Aug 2021 14:16:34 -0700 Subject: [PATCH 49/70] fixes light component GPU test AttributeError (I forgot to update atom_component_helper to atom_constants since constants were split from hydra functions into a new module) (#3115) Signed-off-by: jromnoa --- .../hydra_GPUTest_LightComponent.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_GPUTest_LightComponent.py b/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_GPUTest_LightComponent.py index 08f921e68b..8063445608 100644 --- a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_GPUTest_LightComponent.py +++ b/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_GPUTest_LightComponent.py @@ -23,8 +23,7 @@ import azlmbr.legacy.general as general sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests")) import editor_python_test_tools.hydra_editor_utils as hydra -from atom_renderer.atom_utils import screenshot_utils -from atom_renderer.atom_utils import atom_component_helper +from atom_renderer.atom_utils import atom_component_helper, atom_constants, screenshot_utils from editor_python_test_tools.editor_test_helper import EditorTestHelper helper = EditorTestHelper(log_prefix="Atom_EditorTestHelper") @@ -92,7 +91,7 @@ def area_light_test(): 'SetComponentProperty', light_component_id_pair, LIGHT_TYPE_PROPERTY, - atom_component_helper.LIGHT_TYPES['capsule'] + atom_constants.LIGHT_TYPES['capsule'] ) # Update color and take screenshot in game mode @@ -118,7 +117,7 @@ def area_light_test(): 'SetComponentProperty', light_component_id_pair, LIGHT_TYPE_PROPERTY, - atom_component_helper.LIGHT_TYPES['spot_disk'] + atom_constants.LIGHT_TYPES['spot_disk'] ) area_light_rotation = math.Vector3(DEGREE_RADIAN_FACTOR * 90.0, 0.0, 0.0) azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalRotation", area_light.id, area_light_rotation) @@ -131,7 +130,7 @@ def area_light_test(): 'SetComponentProperty', light_component_id_pair, LIGHT_TYPE_PROPERTY, - atom_component_helper.LIGHT_TYPES['sphere'] + atom_constants.LIGHT_TYPES['sphere'] ) general.idle_wait(1.0) screenshot_utils.take_screenshot_game_mode("AreaLight_5", area_light_entity_name) @@ -210,7 +209,7 @@ def spot_light_test(): 'SetComponentProperty', light_component_type, LIGHT_TYPE_PROPERTY, - atom_component_helper.LIGHT_TYPES['spot_disk'] + atom_constants.LIGHT_TYPES['spot_disk'] ) general.idle_wait(1.0) From 906042359243d215cd05303f732a3422a8fa20a1 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Fri, 13 Aug 2021 16:20:08 -0500 Subject: [PATCH 50/70] Settings registry notification deadlock fix (#3065) * Added a StealHandlers function to AZ Event The StealHandlers function is able to take all the handlers from an AZ Event parameter and register them with the current AZ Event This allows stealing handlers from expiring AZ Events, which is useful for a lock and swap algorithm for thread safety. 1. Lock persistent AZ::Event 2. Swap persistent AZ::Event with local AZ::Event 3. Unlock persistent AZ::Event - Other threads can now add to this AZ::Event 4. Invoke handlers from local AZ::Event 5. Relock persistent AZ::Event 5. Swap local AZ::Event with persistent AZ::Event 6. Local AZ::Event now contains handlers that were added when the lock was free 7. Persistent AZ::Event now steals from local AZ::Event 8. Unlock persistent AZ::Event Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Separated SettingRegistry update/query mutex from Notifier update mutex The Settings Registry update/query mutex is also better scoped to reduce the amount of lock time. The Notifier mutex being separate allows the Settings Registry to signal a notification event without being under any mutex, by locking and swapping the notifier event with a local instance Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Renamed StealHandlers function to ClaimHandlers Replaced decltype keywords in ClaimHandlers to auto Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/EBus/Event.h | 6 + Code/Framework/AzCore/AzCore/EBus/Event.inl | 26 ++++ .../AzCore/Settings/SettingsRegistryImpl.cpp | 111 +++++++++++++----- .../AzCore/Settings/SettingsRegistryImpl.h | 5 +- Code/Framework/AzCore/Tests/EventTests.cpp | 31 +++++ 5 files changed, 151 insertions(+), 28 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/EBus/Event.h b/Code/Framework/AzCore/AzCore/EBus/Event.h index b3c29b63a2..00310f4dbc 100644 --- a/Code/Framework/AzCore/AzCore/EBus/Event.h +++ b/Code/Framework/AzCore/AzCore/EBus/Event.h @@ -58,6 +58,12 @@ namespace AZ Event& operator=(Event&& rhs); + //! Take the handlers registered with the other event + //! and move them to this event. The other will event + //! will be cleared after call + //! @param other event to move handlers + Event& ClaimHandlers(Event&& other); + //! Returns true if at least one handler is connected to this event. bool HasHandlerConnected() const; diff --git a/Code/Framework/AzCore/AzCore/EBus/Event.inl b/Code/Framework/AzCore/AzCore/EBus/Event.inl index dfb1781991..ffa8c8b9c5 100644 --- a/Code/Framework/AzCore/AzCore/EBus/Event.inl +++ b/Code/Framework/AzCore/AzCore/EBus/Event.inl @@ -207,6 +207,32 @@ namespace AZ } + template + auto Event::ClaimHandlers(Event&& other) -> Event& + { + auto handlers = AZStd::move(other.m_handlers); + auto addList = AZStd::move(other.m_addList); + other.m_freeList = {}; + other.m_updating = false; + + AZStd::array handlerContainers{ &handlers, &addList }; + for (AZStd::vector* handlerList : handlerContainers) + { + for (Handler* handler : *handlerList) + { + if (handler != nullptr) + { + handler->m_index = 0; + handler->m_event = this; + Connect(*handler); + } + } + } + + return *this; + } + + template bool Event::HasHandlerConnected() const { diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp index 0882e1b7f2..3dc2d4145e 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp @@ -20,7 +20,7 @@ namespace AZ { template - bool SettingsRegistryImpl::SetValueInternal(AZStd::string_view path, T value, SettingsRegistryInterface::Type type) + bool SettingsRegistryImpl::SetValueInternal(AZStd::string_view path, T value) { if (path.empty()) { @@ -56,7 +56,6 @@ namespace AZ static_assert(!AZStd::is_same_v, "SettingsRegistryImpl::SetValueInternal called with unsupported type."); } - m_notifiers.Signal(path, type); return true; } return false; @@ -157,11 +156,11 @@ namespace AZ // Setting to empty string to prevent assert path = ""; } - AZStd::scoped_lock lock(m_settingMutex); rapidjson::Pointer pointer(path.data(), path.length()); if (pointer.IsValid()) { + AZStd::scoped_lock lock(m_settingMutex); const rapidjson::Value* value = pointer.Get(m_settings); if (value) { @@ -207,7 +206,7 @@ namespace AZ { NotifyEventHandler notifyHandler{ callback }; { - AZStd::scoped_lock lock(m_settingMutex); + AZStd::scoped_lock lock(m_notifierMutex); notifyHandler.Connect(m_notifiers); } return notifyHandler; @@ -217,7 +216,7 @@ namespace AZ { NotifyEventHandler notifyHandler{ AZStd::move(callback) }; { - AZStd::scoped_lock lock(m_settingMutex); + AZStd::scoped_lock lock(m_notifierMutex); notifyHandler.Connect(m_notifiers); } return notifyHandler; @@ -225,10 +224,35 @@ namespace AZ void SettingsRegistryImpl::ClearNotifiers() { - AZStd::scoped_lock lock(m_settingMutex); + AZStd::scoped_lock lock(m_notifierMutex); m_notifiers.DisconnectAllHandlers(); } + void SettingsRegistryImpl::SignalNotifier(AZStd::string_view jsonPath, Type type) + { + // Move the Notifier AZ::Event to a local AZ::Event in order to allow + // the notifier handlers to be signaled outside of the notifier mutex + // This allows other threads to register notifiers while this thread + // is invoking the handlers + decltype(m_notifiers) localNotifierEvent; + { + AZStd::scoped_lock lock(m_notifierMutex); + localNotifierEvent = AZStd::move(m_notifiers); + } + + localNotifierEvent.Signal(jsonPath, type); + + { + // Swap the local handlers with the current m_notifiers which + // will contain any handlers added during the signaling of the + // local event + AZStd::scoped_lock lock(m_notifierMutex); + AZStd::swap(m_notifiers, localNotifierEvent); + // Append any added handlers to the m_notifier structure + m_notifiers.ClaimHandlers(AZStd::move(localNotifierEvent)); + } + } + SettingsRegistryInterface::Type SettingsRegistryImpl::GetType(AZStd::string_view path) const { if (path.empty()) @@ -239,11 +263,11 @@ namespace AZ path = ""; } - AZStd::scoped_lock lock(m_settingMutex); rapidjson::Pointer pointer(path.data(), path.length()); if (pointer.IsValid()) { + AZStd::scoped_lock lock(m_settingMutex); const rapidjson::Value* value = pointer.Get(m_settings); if (value) { @@ -316,11 +340,11 @@ namespace AZ // Setting to empty string to prevent assert path = ""; } - AZStd::scoped_lock lock(m_settingMutex); rapidjson::Pointer pointer(path.data(), path.length()); if (pointer.IsValid()) { + AZStd::scoped_lock lock(m_settingMutex); const rapidjson::Value* value = pointer.Get(m_settings); if (value) { @@ -333,32 +357,52 @@ namespace AZ bool SettingsRegistryImpl::Set(AZStd::string_view path, bool value) { - AZStd::scoped_lock lock(m_settingMutex); - return SetValueInternal(path, value, Type::Boolean); + if (AZStd::scoped_lock lock(m_settingMutex); !SetValueInternal(path, value)) + { + return false; + } + SignalNotifier(path, Type::Boolean); + return true; } bool SettingsRegistryImpl::Set(AZStd::string_view path, s64 value) { - AZStd::scoped_lock lock(m_settingMutex); - return SetValueInternal(path, value, Type::Integer); + if (AZStd::scoped_lock lock(m_settingMutex); !SetValueInternal(path, value)) + { + return false; + } + SignalNotifier(path, Type::Integer); + return true; } bool SettingsRegistryImpl::Set(AZStd::string_view path, u64 value) { - AZStd::scoped_lock lock(m_settingMutex); - return SetValueInternal(path, value, Type::Integer); + if (AZStd::scoped_lock lock(m_settingMutex); !SetValueInternal(path, value)) + { + return false; + } + SignalNotifier(path, Type::Integer); + return true; } bool SettingsRegistryImpl::Set(AZStd::string_view path, double value) { - AZStd::scoped_lock lock(m_settingMutex); - return SetValueInternal(path, value, Type::FloatingPoint); + if (AZStd::scoped_lock lock(m_settingMutex); !SetValueInternal(path, value)) + { + return false; + } + SignalNotifier(path, Type::FloatingPoint); + return true; } bool SettingsRegistryImpl::Set(AZStd::string_view path, AZStd::string_view value) { - AZStd::scoped_lock lock(m_settingMutex); - return SetValueInternal(path, value, Type::String); + if (AZStd::scoped_lock lock(m_settingMutex); !SetValueInternal(path, value)) + { + return false; + } + SignalNotifier(path, Type::String); + return true; } bool SettingsRegistryImpl::Set(AZStd::string_view path, const char* value) @@ -376,7 +420,6 @@ namespace AZ path = ""; } - AZStd::scoped_lock lock(m_settingMutex); rapidjson::Pointer pointer(path.data(), path.length()); if (pointer.IsValid()) @@ -386,9 +429,10 @@ namespace AZ value, nullptr, valueTypeID, m_serializationSettings); if (jsonResult.GetProcessing() != JsonSerializationResult::Processing::Halted) { + AZStd::scoped_lock lock(m_settingMutex); rapidjson::Value& setting = pointer.Create(m_settings, m_settings.GetAllocator()); setting = AZStd::move(store); - m_notifiers.Signal(path, Type::Object); + SignalNotifier(path, Type::Object); return true; } } @@ -404,13 +448,13 @@ namespace AZ // Setting to empty string to prevent assert path = ""; } - AZStd::scoped_lock lock(m_settingMutex); rapidjson::Pointer pointerPath(path.data(), path.size()); if (!pointerPath.IsValid()) { return false; } + AZStd::scoped_lock lock(m_settingMutex); return pointerPath.Erase(m_settings); } @@ -540,7 +584,7 @@ namespace AZ return false; } - m_notifiers.Signal("", Type::Object); + SignalNotifier("", Type::Object); return true; } @@ -562,8 +606,6 @@ namespace AZ scratchBuffer = &buffer; } - AZStd::scoped_lock lock(m_settingMutex); - bool result = false; if (path[path.length()] == 0) { @@ -577,6 +619,8 @@ namespace AZ R"(Path "%.*s" is too long. Either make sure that the provided path is terminated or use a shorter path.)", static_cast(path.length()), path.data()); Pointer pointer(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/-"); + + AZStd::scoped_lock lock(m_settingMutex); Value pathValue(path.data(), aznumeric_caster(path.length()), m_settings.GetAllocator()); pointer.Create(m_settings, m_settings.GetAllocator()).SetObject() .AddMember(StringRef("Error"), StringRef("Unable to read registry file."), m_settings.GetAllocator()) @@ -622,6 +666,7 @@ namespace AZ { AZ_Error("Settings Registry", false, "Folder path for the Setting Registry is too long: %.*s", static_cast(path.size()), path.data()); + AZStd::scoped_lock lock(m_settingMutex); pointer.Create(m_settings, m_settings.GetAllocator()).SetObject() .AddMember(StringRef("Error"), StringRef("Folder path for the Setting Registry is too long."), m_settings.GetAllocator()) .AddMember(StringRef("Path"), Value(path.data(), aznumeric_caster(path.length()), m_settings.GetAllocator()), m_settings.GetAllocator()); @@ -659,6 +704,7 @@ namespace AZ if (fileList.size() >= MaxRegistryFolderEntries) { AZ_Error("Settings Registry", false, "Too many files in registry folder."); + AZStd::scoped_lock lock(m_settingMutex); pointer.Create(m_settings, m_settings.GetAllocator()).SetObject() .AddMember(StringRef("Error"), StringRef("Too many files in registry folder."), m_settings.GetAllocator()) .AddMember(StringRef("Path"), Value(folderPath.c_str(), aznumeric_caster(folderPath.size()), m_settings.GetAllocator()), m_settings.GetAllocator()) @@ -678,7 +724,6 @@ namespace AZ SystemFile::FindFiles(folderPath.c_str(), callback); - AZStd::scoped_lock lock(m_settingMutex); if (!platform.empty()) { // Move the folderPath prefix back to the supplied path before the wildcard @@ -696,6 +741,7 @@ namespace AZ if (fileList.size() >= MaxRegistryFolderEntries) { AZ_Error("Settings Registry", false, "Too many files in registry folder."); + AZStd::scoped_lock lock(m_settingMutex); pointer.Create(m_settings, m_settings.GetAllocator()).SetObject() .AddMember(StringRef("Error"), StringRef("Too many files in registry folder."), m_settings.GetAllocator()) .AddMember(StringRef("Path"), Value(folderPath.c_str(), aznumeric_caster(folderPath.size()), m_settings.GetAllocator()), m_settings.GetAllocator()) @@ -923,6 +969,8 @@ namespace AZ collisionFound = true; AZ_Error("Settings Registry", false, R"(Two registry files in "%.*s" point to the same specialization: "%s" and "%s")", AZ_STRING_ARG(folderPath), lhs.m_relativePath.c_str(), rhs.m_relativePath.c_str()); + + AZStd::scoped_lock lock(m_settingMutex); historyPointer.Create(m_settings, m_settings.GetAllocator()).SetObject() .AddMember(StringRef("Error"), StringRef("Too many files in registry folder."), m_settings.GetAllocator()) .AddMember(StringRef("Path"), @@ -1077,6 +1125,7 @@ namespace AZ } } + AZStd::scoped_lock lock(m_settingMutex); pointer.Create(m_settings, m_settings.GetAllocator()).SetObject() .AddMember(StringRef("Error"), StringRef("Unable to parse registry file due to invalid json."), m_settings.GetAllocator()) .AddMember(StringRef("Path"), Value(path, m_settings.GetAllocator()), m_settings.GetAllocator()) @@ -1102,6 +1151,7 @@ namespace AZ R"(To merge the supplied settings registry file, the settings within it must be placed within a JSON Object '{}')" R"( in order to allow moving of its fields using the root-key as an anchor.)", path); + AZStd::scoped_lock lock(m_settingMutex); pointer.Create(m_settings, m_settings.GetAllocator()).SetObject() .AddMember(StringRef("Error"), StringRef("Cannot merge registry file with a root which is not a JSON Object," " an empty root key and a merge approach of JsonMergePatch. Otherwise the Settings Registry would be overridden." @@ -1118,6 +1168,7 @@ namespace AZ JsonSerializationResult::ResultCode mergeResult(JsonSerializationResult::Tasks::Merge); if (rootKey.empty()) { + AZStd::scoped_lock lock(m_settingMutex); mergeResult = JsonSerialization::ApplyPatch(m_settings, m_settings.GetAllocator(), jsonPatch, mergeApproach, m_applyPatchSettings); } else @@ -1125,6 +1176,7 @@ namespace AZ Pointer root(rootKey.data(), rootKey.length()); if (root.IsValid()) { + AZStd::scoped_lock lock(m_settingMutex); Value& rootValue = root.Create(m_settings, m_settings.GetAllocator()); mergeResult = JsonSerialization::ApplyPatch(rootValue, m_settings.GetAllocator(), jsonPatch, mergeApproach, m_applyPatchSettings); } @@ -1132,6 +1184,7 @@ namespace AZ { AZ_Error("Settings Registry", false, R"(Failed to root path "%.*s" is invalid.)", aznumeric_cast(rootKey.length()), rootKey.data()); + AZStd::scoped_lock lock(m_settingMutex); pointer.Create(m_settings, m_settings.GetAllocator()).SetObject() .AddMember(StringRef("Error"), StringRef("Invalid root key."), m_settings.GetAllocator()) .AddMember(StringRef("Path"), Value(path, m_settings.GetAllocator()), m_settings.GetAllocator()); @@ -1141,15 +1194,19 @@ namespace AZ if (mergeResult.GetProcessing() != JsonSerializationResult::Processing::Completed) { AZ_Error("Settings Registry", false, R"(Failed to fully merge registry file "%s".)", path); + AZStd::scoped_lock lock(m_settingMutex); pointer.Create(m_settings, m_settings.GetAllocator()).SetObject() .AddMember(StringRef("Error"), StringRef("Failed to fully merge registry file."), m_settings.GetAllocator()) .AddMember(StringRef("Path"), Value(path, m_settings.GetAllocator()), m_settings.GetAllocator()); return false; } - pointer.Create(m_settings, m_settings.GetAllocator()).SetString(path, m_settings.GetAllocator()); + { + AZStd::scoped_lock lock(m_settingMutex); + pointer.Create(m_settings, m_settings.GetAllocator()).SetString(path, m_settings.GetAllocator()); + } - m_notifiers.Signal("", Type::Object); + SignalNotifier("", Type::Object); return true; } diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.h b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.h index 41a628cf22..4126e19322 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.h +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.h @@ -89,7 +89,7 @@ namespace AZ using RegistryFileList = AZStd::fixed_vector; template - bool SetValueInternal(AZStd::string_view path, T value, SettingsRegistryInterface::Type type); + bool SetValueInternal(AZStd::string_view path, T value); template bool GetValueInternal(T& result, AZStd::string_view path) const; VisitResponse Visit(Visitor& visitor, StackedString& path, AZStd::string_view valueName, @@ -100,8 +100,11 @@ namespace AZ const rapidjson::Pointer& historyPointer, AZStd::string_view folderPath); bool ExtractFileDescription(RegistryFile& output, const char* filename, const Specializations& specializations); bool MergeSettingsFileInternal(const char* path, Format format, AZStd::string_view rootKey, AZStd::vector& scratchBuffer); + + void SignalNotifier(AZStd::string_view jsonPath, Type type); mutable AZStd::recursive_mutex m_settingMutex; + mutable AZStd::recursive_mutex m_notifierMutex; NotifyEvent m_notifiers; rapidjson::Document m_settings; JsonSerializerSettings m_serializationSettings; diff --git a/Code/Framework/AzCore/Tests/EventTests.cpp b/Code/Framework/AzCore/Tests/EventTests.cpp index 358c1a62ae..aaa70344e7 100644 --- a/Code/Framework/AzCore/Tests/EventTests.cpp +++ b/Code/Framework/AzCore/Tests/EventTests.cpp @@ -240,6 +240,37 @@ namespace UnitTest static_assert(!AZStd::is_copy_assignable_v>, "AZ Events should not be copy assignable"); } + TEST_F(EventTests, TestClaimHandlers_TakesAllSourceHandlers) + { + AZ::Event<> testEvent1; + AZ::Event<> testEvent2; + + int32_t handlerInvokeCount{}; + auto handlerCallback = [&handlerInvokeCount]() + { + ++handlerInvokeCount; + }; + AZ::Event<>::Handler testHandler1(handlerCallback); + AZ::Event<>::Handler testHandler2(handlerCallback); + + testHandler1.Connect(testEvent1); + testHandler2.Connect(testEvent2); + + EXPECT_TRUE(testEvent1.HasHandlerConnected()); + EXPECT_TRUE(testEvent2.HasHandlerConnected()); + + testEvent1.ClaimHandlers(AZStd::move(testEvent2)); + EXPECT_TRUE(testEvent1.HasHandlerConnected()); + EXPECT_FALSE(testEvent2.HasHandlerConnected()); + + // testEvent1 should have both handlers + testEvent1.Signal(); + EXPECT_EQ(2, handlerInvokeCount); + // testEvent2 should have neither of the handlers + testEvent2.Signal(); + EXPECT_EQ(2, handlerInvokeCount); + } + TEST_F(EventTests, HandlerMoveAssignment_ProperlyDisconnectsFromOldEvent) { AZ::Event<> testEvent1; From 093a03cfbc98993d799883d9426ef3a7fda1a6a8 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Fri, 13 Aug 2021 15:58:01 -0700 Subject: [PATCH 51/70] fix for non-unity mac build (#3118) Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Editor/Util/StringHelpers.cpp | 2 -- Code/Editor/Util/StringHelpers.h | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Code/Editor/Util/StringHelpers.cpp b/Code/Editor/Util/StringHelpers.cpp index 6c819270bd..d0999d6ae2 100644 --- a/Code/Editor/Util/StringHelpers.cpp +++ b/Code/Editor/Util/StringHelpers.cpp @@ -10,8 +10,6 @@ #include "StringHelpers.h" #include "Util.h" -#include - int StringHelpers::CompareIgnoreCase(const AZStd::string& str0, const AZStd::string& str1) { const size_t minLength = Util::getMin(str0.length(), str1.length()); diff --git a/Code/Editor/Util/StringHelpers.h b/Code/Editor/Util/StringHelpers.h index b5c84d7fe3..8a0883b24c 100644 --- a/Code/Editor/Util/StringHelpers.h +++ b/Code/Editor/Util/StringHelpers.h @@ -12,7 +12,7 @@ #pragma once #include -#include +#include namespace StringHelpers { From 693b205747809ab0b6804fdd6975654e37c17cc4 Mon Sep 17 00:00:00 2001 From: kberg-amzn Date: Fri, 13 Aug 2021 16:56:27 -0700 Subject: [PATCH 52/70] Removing debug code, and fixing vector/array not respecting replication record dirty bits Signed-off-by: kberg-amzn --- .../Code/Source/AutoGen/AutoComponent_Source.jinja | 11 +++++------ .../Code/Source/Components/NetBindComponent.cpp | 2 -- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja index d2be2f682a..56ab828ffe 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja @@ -643,16 +643,15 @@ bool {{ ClassName }}::Serialize{{ AutoComponentMacros.GetNetPropertiesSetName(Re const uint32_t lastBit = static_cast({{ AutoComponentMacros.GetNetPropertiesQualifiedPropertyDirtyEnum(Component.attrib['Name'], ReplicateFrom, ReplicateTo, Property, 'End') }}); {% endif %} -{% if Property.attrib['IsRewindable']|booleanTrue %} AzNetworking::FixedSizeBitsetView deltaRecord(replicationRecord.m_{{ LowerFirst(AutoComponentMacros.GetNetPropertiesSetName(ReplicateFrom, ReplicateTo)) }}, firstBit, lastBit - firstBit + 1); - m_{{ LowerFirst(Property.attrib['Name']) }}.Serialize(serializer, deltaRecord); -{% else %} + if (deltaRecord.AnySet()) + { {% if Property.attrib['Container'] == 'Vector' %} - serializer.Serialize>(m_{{ LowerFirst(Property.attrib['Name']) }}, "{{ LowerFirst(Property.attrib['Name']) }}"); + serializer.Serialize>(m_{{ LowerFirst(Property.attrib['Name']) }}, "{{ LowerFirst(Property.attrib['Name']) }}"); {% elif Property.attrib['Container'] == 'Array' %} - serializer.Serialize>(m_{{ LowerFirst(Property.attrib['Name']) }}, "{{ LowerFirst(Property.attrib['Name']) }}"); + serializer.Serialize>(m_{{ LowerFirst(Property.attrib['Name']) }}, "{{ LowerFirst(Property.attrib['Name']) }}"); {% endif %} -{% endif %} + } } {% else %} Multiplayer::SerializeNetworkPropertyHelper diff --git a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp index dfe2b6b561..d8e8a765ce 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp @@ -284,8 +284,6 @@ namespace Multiplayer void NetBindComponent::ProcessInput(NetworkInput& networkInput, float deltaTime) { - AZ_TracePrintf("gathers", "Processing input, inputId=%d", static_cast(networkInput.GetClientInputId())); - m_isProcessingInput = true; // Only autonomous and authority runs this logic AZ_Assert((NetworkRoleHasController(m_netEntityRole)), "Incorrect network role for input processing"); From 87ae7e865365707ba7d7fc453fdd0c43b34f489a Mon Sep 17 00:00:00 2001 From: Steve Pham <82231385+spham-amzn@users.noreply.github.com> Date: Fri, 13 Aug 2021 18:22:40 -0700 Subject: [PATCH 53/70] Fix android gradle scripts to prevent cmake_dependencies.._gamelauncher from being wiped out of the APK Update gradle script generation to correct task dependencies (#3120) - copyNativeArtifacts must run after syncLYLayoutMode - syncLYLayoutMode must must after externalNativeBuild Signed-off-by: Steve Pham --- .../Tools/Platform/Android/android_support.py | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/cmake/Tools/Platform/Android/android_support.py b/cmake/Tools/Platform/Android/android_support.py index d820eb1d8c..77c8a37a35 100755 --- a/cmake/Tools/Platform/Android/android_support.py +++ b/cmake/Tools/Platform/Android/android_support.py @@ -372,9 +372,12 @@ CUSTOM_GRADLE_COPY_NATIVE_CONFIG_BUILD_ARTIFACTS_FORMAT_STR = """ }} compile{config}Sources.dependsOn copyNativeArtifacts{config} +""" + +CUSTOM_GRADLE_COPY_NATIVE_CONFIG_BUILD_ARTIFACTS_DEPENDENCY_FORMAT_STR = """ copyNativeArtifacts{config}.mustRunAfter {{ - tasks.findAll {{ task->task.name.contains('externalNativeBuild{config}') }} + tasks.findAll {{ task->task.name.contains('syncLYLayoutMode{config}') }} }} """ @@ -383,7 +386,13 @@ CUSTOM_APPLY_ASSET_LAYOUT_TASK_FORMAT_STR = """ workingDir '{working_dir}' commandLine '{python_full_path}', 'layout_tool.py', '--project-path', '{project_path}', '-p', 'Android', '-a', '{asset_type}', '-m', '{asset_mode}', '--create-layout-root', '-l', '{asset_layout_folder}' }} + compile{config}Sources.dependsOn syncLYLayoutMode{config} + + syncLYLayoutMode{config}.mustRunAfter {{ + tasks.findAll {{ task->task.name.contains('externalNativeBuild{config}') }} + }} + """ @@ -832,25 +841,28 @@ class AndroidProjectGenerator(object): asset_layout_folder=(self.build_dir / 'app/src/main/assets').resolve().as_posix(), file_includes='Test.Assets/**/*.*') else: - # Copy over settings registry files from the Registry folder with build output directory gradle_build_env[f'CUSTOM_APPLY_ASSET_LAYOUT_{native_config_upper}_TASK'] = \ + CUSTOM_APPLY_ASSET_LAYOUT_TASK_FORMAT_STR.format(working_dir=common.normalize_path_for_settings(self.engine_root / 'cmake/Tools'), + python_full_path=common.normalize_path_for_settings(self.engine_root / 'python' / PYTHON_SCRIPT), + asset_type=self.asset_type, + project_path=self.project_path.as_posix(), + asset_mode=self.asset_mode if native_config != 'Release' else 'PAK', + asset_layout_folder=(self.build_dir / 'app/src/main/assets').resolve().as_posix(), + config=native_config) + # Copy over settings registry files from the Registry folder with build output directory + gradle_build_env[f'CUSTOM_APPLY_ASSET_LAYOUT_{native_config_upper}_TASK'] += \ CUSTOM_GRADLE_COPY_NATIVE_CONFIG_BUILD_ARTIFACTS_FORMAT_STR.format(config=native_config, config_lower=native_config_lower, asset_layout_folder=(self.build_dir / 'app/src/main/assets').resolve().as_posix(), file_includes='**/Registry/*.setreg') - - if self.include_assets_in_apk: - if not self.is_test_project: + if self.include_assets_in_apk: + # This is a dependency of the layout sync only if we are including assets in the APK gradle_build_env[f'CUSTOM_APPLY_ASSET_LAYOUT_{native_config_upper}_TASK'] += \ - CUSTOM_APPLY_ASSET_LAYOUT_TASK_FORMAT_STR.format(working_dir=common.normalize_path_for_settings(self.engine_root / 'cmake/Tools'), - python_full_path=common.normalize_path_for_settings(self.engine_root / 'python' / PYTHON_SCRIPT), - asset_type=self.asset_type, - project_path=self.project_path.as_posix(), - asset_mode=self.asset_mode if native_config != 'Release' else 'PAK', - asset_layout_folder=(self.build_dir / 'app/src/main/assets').resolve().as_posix(), - config=native_config) - else: - gradle_build_env[f'CUSTOM_APPLY_ASSET_LAYOUT_{native_config_upper}_TASK'] = '' + CUSTOM_GRADLE_COPY_NATIVE_CONFIG_BUILD_ARTIFACTS_DEPENDENCY_FORMAT_STR.format(config=native_config) + + + + if self.signing_config: gradle_build_env[f'SIGNING_{native_config_upper}_CONFIG'] = f'signingConfig signingConfigs.{native_config_lower}' if self.signing_config else '' else: From 2fa9a831b3d09240d786d0636a173f9c9d169fd7 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Fri, 13 Aug 2021 20:26:49 -0500 Subject: [PATCH 54/70] AtomTools: prepend asterisk to denote modified document tabs Appending is standard and preferred but the tabs elide from the end (instead of middle) and cut it off Signed-off-by: Guthrie Adams --- .../Code/Source/Window/AtomToolsMainWindow.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp index 55bec32dc7..e869e0eb98 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp @@ -199,8 +199,10 @@ namespace AtomToolsFramework { if (documentId == GetDocumentIdFromTab(tabIndex)) { - // We use an asterisk appended to the file name to denote modified document - const AZStd::string modifiedLabel = isModified ? label + " *" : label; + // We use an asterisk prepended to the file name to denote modified document + // Appending is standard and preferred but the tabs elide from the + // end (instead of middle) and cut it off + const AZStd::string modifiedLabel = isModified ? "* " + label : label; m_tabWidget->setTabText(tabIndex, modifiedLabel.c_str()); m_tabWidget->setTabToolTip(tabIndex, toolTip.c_str()); m_tabWidget->repaint(); From 83f6cb813ae42e0e8420a48f791d5c52f3f3178c Mon Sep 17 00:00:00 2001 From: Steve Pham <82231385+spham-amzn@users.noreply.github.com> Date: Fri, 13 Aug 2021 18:38:48 -0700 Subject: [PATCH 55/70] Fix Non-Unity compile error with Atom Sample Viewer and the Atom Gem (#3119) Signed-off-by: spham-amzn --- Gems/Atom/Utils/Code/Include/Atom/Utils/StableDynamicArray.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/StableDynamicArray.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/StableDynamicArray.h index 7c77838330..454a6d4086 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/StableDynamicArray.h +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/StableDynamicArray.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include From fe3b30e42ca96e97c4609de60daacde6d3f4fe60 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sat, 14 Aug 2021 14:07:36 -0500 Subject: [PATCH 56/70] AtomTools: Fix python terminal help crash ATOM-16242 Checking EditorWindowRequests::GetAppMainWindow before searching for main window Signed-off-by: Guthrie Adams --- .../PythonTerminal/ScriptHelpDialog.cpp | 41 ++++++++++++++++++- .../PythonTerminal/ScriptHelpDialog.h | 34 +-------------- 2 files changed, 42 insertions(+), 33 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/PythonTerminal/ScriptHelpDialog.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/PythonTerminal/ScriptHelpDialog.cpp index ea13d368cd..ba85911060 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/PythonTerminal/ScriptHelpDialog.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/PythonTerminal/ScriptHelpDialog.cpp @@ -6,7 +6,6 @@ * */ - // Description : For listing available script commands with their descriptions #include "ScriptHelpDialog.h" @@ -23,6 +22,7 @@ // AzToolsFramework #include // for EditorPythonConsoleInterface +#include AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING #include @@ -313,6 +313,45 @@ namespace AzToolsFramework connect(ui->tableView, &ScriptTableView::doubleClicked, this, &CScriptHelpDialog::OnDoubleClick); } + CScriptHelpDialog* CScriptHelpDialog::GetInstance() + { + static CScriptHelpDialog* pInstance = nullptr; + if (!pInstance) + { + QMainWindow* mainWindow = GetMainWindowOfCurrentApplication(); + if (!mainWindow) + { + AZ_Assert(false, "Failed to find MainWindow."); + return nullptr; + } + + QWidget* parentWidget = mainWindow->window() + ? mainWindow->window() + : mainWindow; // MainWindow might have a WindowDecorationWrapper parent. Makes a difference on macOS. + pInstance = new CScriptHelpDialog(parentWidget); + } + return pInstance; + } + + QMainWindow* CScriptHelpDialog::GetMainWindowOfCurrentApplication() + { + QWidget* widget = nullptr; + EditorWindowRequestBus::BroadcastResult(widget, &EditorWindowRequests::GetAppMainWindow); + if (QMainWindow* mainWindow = qobject_cast(widget)) + { + return mainWindow; + } + + for (QWidget* widget : qApp->topLevelWidgets()) + { + if (QMainWindow* mainWindow = qobject_cast(widget)) + { + return mainWindow; + } + } + return nullptr; + } + void CScriptHelpDialog::OnDoubleClick(const QModelIndex& index) { if (!index.isValid()) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/PythonTerminal/ScriptHelpDialog.h b/Code/Framework/AzToolsFramework/AzToolsFramework/PythonTerminal/ScriptHelpDialog.h index e34d652e1b..3cefa919c9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/PythonTerminal/ScriptHelpDialog.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/PythonTerminal/ScriptHelpDialog.h @@ -132,43 +132,13 @@ namespace AzToolsFramework { Q_OBJECT public: - static CScriptHelpDialog* GetInstance() - { - static CScriptHelpDialog* pInstance = nullptr; - if (!pInstance) - { - QMainWindow* mainWindow = GetMainWindowOfCurrentApplication(); - if (!mainWindow) - { - AZ_Assert(false, "Failed to find MainWindow."); - return nullptr; - } - - QWidget* parentWidget = mainWindow->window() ? mainWindow->window() : mainWindow; // MainWindow might have a WindowDecorationWrapper parent. Makes a difference on macOS. - pInstance = new CScriptHelpDialog(parentWidget); - } - return pInstance; - } - + static CScriptHelpDialog* GetInstance(); private Q_SLOTS: void OnDoubleClick(const QModelIndex&); private: - static QMainWindow* GetMainWindowOfCurrentApplication() - { - QMainWindow* mainWindow = nullptr; - for (QWidget* w : qApp->topLevelWidgets()) - { - mainWindow = qobject_cast(w); - if (mainWindow) - { - return mainWindow; - } - } - return nullptr; - } - explicit CScriptHelpDialog(QWidget* parent = nullptr); + static QMainWindow* GetMainWindowOfCurrentApplication(); QScopedPointer ui; }; } // namespace AzToolsFramework From d6c5f1444ba8595df24ce84776a8fec881377e72 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sat, 14 Aug 2021 14:30:54 -0500 Subject: [PATCH 57/70] fixing hidden variable warning Signed-off-by: Guthrie Adams --- .../PythonTerminal/ScriptHelpDialog.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/PythonTerminal/ScriptHelpDialog.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/PythonTerminal/ScriptHelpDialog.cpp index ba85911060..e9f6cd9e53 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/PythonTerminal/ScriptHelpDialog.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/PythonTerminal/ScriptHelpDialog.cpp @@ -335,16 +335,16 @@ namespace AzToolsFramework QMainWindow* CScriptHelpDialog::GetMainWindowOfCurrentApplication() { - QWidget* widget = nullptr; - EditorWindowRequestBus::BroadcastResult(widget, &EditorWindowRequests::GetAppMainWindow); - if (QMainWindow* mainWindow = qobject_cast(widget)) + QWidget* mainWindowWidget = nullptr; + EditorWindowRequestBus::BroadcastResult(mainWindowWidget, &EditorWindowRequests::GetAppMainWindow); + if (QMainWindow* mainWindow = qobject_cast(mainWindowWidget)) { return mainWindow; } - for (QWidget* widget : qApp->topLevelWidgets()) + for (QWidget* topLevelWidget : qApp->topLevelWidgets()) { - if (QMainWindow* mainWindow = qobject_cast(widget)) + if (QMainWindow* mainWindow = qobject_cast(topLevelWidget)) { return mainWindow; } From 181698b950e63236d77c525964d9af5bbe617932 Mon Sep 17 00:00:00 2001 From: sphrose <82213493+sphrose@users.noreply.github.com> Date: Mon, 16 Aug 2021 10:54:15 +0100 Subject: [PATCH 58/70] LY-91616 Dyn Veg: Push (up) and Pop (down) Items in Descriptor List (#3013) * LY-91616 Dyn Veg: Push (up) and Pop (down) Items in Descriptor List Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> * Changes as per reviews. Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> * Additional review changes. Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> * review change Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> --- .../Components/FancyDocking.cpp | 5 +- .../PropertyEditor/EntityPropertyEditor.cpp | 1117 ++++++++++++++--- .../PropertyEditor/EntityPropertyEditor.hxx | 70 +- .../UI/PropertyEditor/PropertyRowWidget.cpp | 183 ++- .../UI/PropertyEditor/PropertyRowWidget.hxx | 21 + .../ReflectedPropertyEditor.cpp | 224 +++- .../ReflectedPropertyEditor.hxx | 10 + 7 files changed, 1441 insertions(+), 189 deletions(-) diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/FancyDocking.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/FancyDocking.cpp index c5aa1a3f88..4ced4ea635 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/FancyDocking.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/FancyDocking.cpp @@ -1882,7 +1882,10 @@ namespace AzQtComponents return; } - QApplication::setOverrideCursor(m_dragCursor); + if (!QApplication::overrideCursor()) + { + QApplication::setOverrideCursor(m_dragCursor); + } QPoint relativePressPos = pressPos; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp index f166e85ff9..2c46bb2d26 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp @@ -16,6 +16,7 @@ AZ_POP_DISABLE_WARNING #include #include #include +#include #include #include #include @@ -106,7 +107,11 @@ void initEntityPropertyEditorResources() namespace AzToolsFramework { - static const char* kComponentEditorIndexMimeType = "editor/componentEditorIndices"; + constexpr const char* kComponentEditorIndexMimeType = "editor/componentEditorIndices"; + constexpr const char* kComponentEditorRowWidgetType = "editor/componentEditorRowWidget"; + + constexpr const char* kPropertyEditorMenuActionMoveUp("editor/propertyEditorMoveUp"); + constexpr const char* kPropertyEditorMenuActionMoveDown("editor/propertyEditorMoveDown"); //since component editors are spaced apart to make room for drop indicator, //giving drop logic simple buffer so drops between editors don't go to the bottom @@ -149,6 +154,7 @@ namespace AzToolsFramework : QWidget(parent) , m_editor(editor) , m_dropIndicatorOffset(8) + , m_dropIndicatorRowWidgetOffset(2) { setPalette(Qt::transparent); setWindowFlags(Qt::FramelessWindowHint); @@ -158,22 +164,137 @@ namespace AzToolsFramework } protected: - void paintEvent(QPaintEvent* event) override + static constexpr int TopMargin = 1; + static constexpr int RightMargin = 2; + static constexpr int BottomMargin = 5; + static constexpr int LeftMargin = 2; + static constexpr int RowHighlightIndent = 2; + + void paintDraggingRowWidget(QPainter& painter) { - const int TopMargin = 1; - const int RightMargin = 2; - const int BottomMargin = 5; - const int LeftMargin = 2; + ComponentEditor* rowWidgetEditor = m_editor->GetEditorForCurrentReorderRowWidget(); + PropertyRowWidget* dragRowWidget = m_editor->GetReorderRowWidget(); + PropertyRowWidget* dropTarget = m_editor->GetReorderDropTarget(); + EntityPropertyEditor::DropArea dropArea = m_editor->GetReorderDropArea(); - QWidget::paintEvent(event); + // The user is dragging a row widget. + for (auto componentEditor : m_editor->m_componentEditors) + { + if (!componentEditor->isVisible()) + { + continue; + } - QPainter painter(this); - painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + if (componentEditor != rowWidgetEditor) + { + continue; + } - QRect currRect; + for (auto& [dataNode, rowWidget] : componentEditor->GetPropertyEditor()->GetWidgets()) + { + if (!rowWidget->isVisible()) + { + continue; + } + + QRect globalRect = m_editor->GetWidgetAndVisibleChildrenGlobalRect(rowWidget); + + QRect currRect = QRect( + QPoint(mapFromGlobal(globalRect.topLeft()) + QPoint(LeftMargin, TopMargin)), + QPoint(mapFromGlobal(globalRect.bottomRight()) - QPoint(RightMargin, BottomMargin))); + + currRect.setLeft(LeftMargin + RowHighlightIndent); + currRect.setWidth(rowWidget->GetContainingEditorFrameWidth() - (RightMargin + LeftMargin)); + + if (rowWidget == dragRowWidget) + { + QStyleOption opt; + opt.init(this); + opt.rect = currRect; + qobject_cast (style())->drawDragIndicator(&opt, &painter, this); + } + + if (rowWidget == dropTarget) + { + QRect dropRect = currRect; + if (dropArea == EntityPropertyEditor::DropArea::Above) + { + dropRect.setTop(currRect.top() - m_dropIndicatorRowWidgetOffset); + } + else + { + dropRect.setTop(currRect.bottom()); + } + + dropRect.setHeight(0); + + QStyleOption opt; + opt.init(this); + opt.rect = dropRect; + style()->drawPrimitive(QStyle::PE_IndicatorItemViewItemDrop, &opt, &painter, this); + } + } + } + }; + + void paintMenuHighlight(QPainter& painter, float alpha) + { + // If a RowWidget can be moved up or down, highlight it. + PropertyRowWidget* dragRowWidget = m_editor->GetReorderRowWidget(); + if (!dragRowWidget) + { + return; + } + + PropertyRowWidget* dropTarget = m_editor->GetReorderDropTarget(); + EntityPropertyEditor::DropArea dropArea = m_editor->GetReorderDropArea(); + QPixmap dragImage = m_editor->GetReorderRowWidgetImage(); + + // User has the context menu open with a movable row selected. + QRect globalRect = m_editor->GetWidgetAndVisibleChildrenGlobalRect(dragRowWidget); + + int top = mapFromGlobal(globalRect.topLeft()).y(); + int imageHeight = dragImage.height() / dragImage.devicePixelRatioF(); + int imageWidth = dragImage.width() / dragImage.devicePixelRatioF(); + QRect currRect = QRect(QPoint(LeftMargin + 1, top), QPoint(LeftMargin + 1 + imageWidth, top + imageHeight)); + + painter.setOpacity(alpha); + painter.drawPixmap(currRect, dragImage); + + if (dropTarget) + { + // A move row menu command is highlighted. Draw an indicator to show where the current row will move to. + globalRect = m_editor->GetWidgetAndVisibleChildrenGlobalRect(dropTarget); + QRect dropRect = QRect( + QPoint(mapFromGlobal(globalRect.topLeft()) + QPoint(LeftMargin, TopMargin)), + QPoint(mapFromGlobal(globalRect.bottomRight()) - QPoint(RightMargin, TopMargin))); + + if (dropArea == EntityPropertyEditor::DropArea::Above) + { + dropRect.setTop(dropRect.top() - m_dropIndicatorRowWidgetOffset); + } + else + { + dropRect.setTop(dropRect.bottom()); + } + dropRect.setHeight(0); + + painter.setOpacity(alpha); + QStyleOption lineOpt; + lineOpt.init(this); + lineOpt.rect = dropRect; + style()->drawPrimitive(QStyle::PE_IndicatorItemViewItemDrop, &lineOpt, &painter, this); + painter.setOpacity(1.0f); + } + }; + + void paintDraggingComponent(QPainter& painter) + { bool drag = false; bool drop = false; + QRect currRect; + // Check for a component editor being dragged. for (auto componentEditor : m_editor->m_componentEditors) { if (!componentEditor->isVisible()) @@ -185,8 +306,7 @@ namespace AzToolsFramework currRect = QRect( QPoint(mapFromGlobal(globalRect.topLeft()) + QPoint(LeftMargin, TopMargin)), - QPoint(mapFromGlobal(globalRect.bottomRight()) - QPoint(RightMargin, BottomMargin)) - ); + QPoint(mapFromGlobal(globalRect.bottomRight()) - QPoint(RightMargin, BottomMargin))); currRect.setWidth(currRect.width() - 1); currRect.setHeight(currRect.height() - 1); @@ -226,6 +346,67 @@ namespace AzToolsFramework opt.rect = dropRect; style()->drawPrimitive(QStyle::PE_IndicatorItemViewItemDrop, &opt, &painter, this); } + }; + + void paintMovedRow(QPainter& painter, float alpha) + { + // After a move has been carried out, briefly highlight the moved row. + PropertyRowWidget* rowWidget = m_editor->GetRowToHighlight(); + + if (!rowWidget) + { + return; + } + + QRect globalRect = m_editor->GetWidgetAndVisibleChildrenGlobalRect(rowWidget); + QRect currRect = QRect( + QPoint(mapFromGlobal(globalRect.topLeft()) + QPoint(LeftMargin, TopMargin)), + QPoint(mapFromGlobal(globalRect.bottomRight()) - QPoint(RightMargin, BottomMargin))); + + currRect.setLeft(LeftMargin + 2); + currRect.setWidth(rowWidget->GetContainingEditorFrameWidth() - (RightMargin + LeftMargin)); + + painter.setOpacity(alpha); + + QPen pen; + QColor drawColor = Qt::white; + drawColor.setAlphaF(alpha); + pen.setColor(drawColor); + pen.setWidth(1); + painter.setPen(pen); + painter.drawRect(currRect); + } + + void paintEvent(QPaintEvent* event) override + { + QWidget::paintEvent(event); + + QPainter painter(this); + painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + + EntityPropertyEditor::ReorderState currentState = m_editor->GetReorderState(); + float indicatorAlpha = m_editor->GetMoveIndicatorAlpha(); + + switch (currentState) + { + case EntityPropertyEditor::ReorderState::DraggingRowWidget: + paintDraggingRowWidget(painter); + break; + case EntityPropertyEditor::ReorderState::UsingMenu: + paintMenuHighlight(painter, 1.0f); + break; + case EntityPropertyEditor::ReorderState::MenuOperationInProgress: + paintMenuHighlight(painter, indicatorAlpha); + break; + case EntityPropertyEditor::ReorderState::DraggingComponent: + paintDraggingComponent(painter); + break; + case EntityPropertyEditor::ReorderState::HighlightMovedRow: + paintMovedRow(painter, indicatorAlpha); + break; + default: + break; + } } bool event(QEvent* ev) override @@ -280,6 +461,7 @@ namespace AzToolsFramework private: EntityPropertyEditor* m_editor; int m_dropIndicatorOffset; + int m_dropIndicatorRowWidgetOffset; }; EntityPropertyEditor::SharedComponentInfo::SharedComponentInfo(AZ::Component* component, AZ::Component* sliceReferenceComponent) @@ -382,6 +564,9 @@ namespace AzToolsFramework m_emptyIcon = QIcon(); m_clearIcon = QIcon(":/AssetBrowser/Resources/close.png"); + m_dragIcon = QIcon(QStringLiteral(":/Cursors/Grabbing.svg")); + m_dragCursor = QCursor(m_dragIcon.pixmap(16), 10, 5); + m_serializeContext = nullptr; AZ::ComponentApplicationBus::BroadcastResult(m_serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext); AZ_Assert(m_serializeContext, "Failed to acquire application serialize context."); @@ -1867,6 +2052,12 @@ namespace AzToolsFramework return; } + // Don't show if a move operation is pending. + if (m_currentReorderState != ReorderState::Inactive) + { + return; + } + // Locate the owning component and class data corresponding to the clicked node. InstanceDataNode* componentNode = node; while (componentNode->GetParent()) @@ -1905,7 +2096,12 @@ namespace AzToolsFramework if (!menu.actions().empty()) { + m_currentReorderState = EntityPropertyEditor::ReorderState::UsingMenu; menu.exec(position); + if (m_currentReorderState != EntityPropertyEditor::ReorderState::MenuOperationInProgress) + { + m_currentReorderState = EntityPropertyEditor::ReorderState::Inactive; + } } } } @@ -1956,129 +2152,179 @@ namespace AzToolsFramework AZ::SliceComponent* rootSlice = nullptr; AzFramework::SliceEntityOwnershipServiceRequestBus::EventResult(rootSlice, contextId, &AzFramework::SliceEntityOwnershipServiceRequestBus::Events::GetRootSlice); - if (!rootSlice) + if (rootSlice) { - return; - } - - AZ::SliceComponent::SliceInstanceAddress address; - AzFramework::SliceEntityRequestBus::EventResult(address, entity->GetId(), - &AzFramework::SliceEntityRequests::GetOwningSlice); - AZ::SliceComponent::SliceReference* sliceReference = address.GetReference(); - if (sliceReference) - { - // This entity is instanced from a slice, so show data push/pull options - AZ::SliceComponent::EntityAncestorList ancestors; - sliceReference->GetInstanceEntityAncestry(entity->GetId(), ancestors); - - AZ_Error("PropertyEditor", !ancestors.empty(), "Entity \"%s\" belongs to a slice, but its source entity could not be located.", entity->GetName().c_str()); - if (!ancestors.empty()) + AZ::SliceComponent::SliceInstanceAddress address; + AzFramework::SliceEntityRequestBus::EventResult(address, entity->GetId(), &AzFramework::SliceEntityRequests::GetOwningSlice); + AZ::SliceComponent::SliceReference* sliceReference = address.GetReference(); + if (sliceReference) { - menu.addSeparator(); + // This entity is instanced from a slice, so show data push/pull options + AZ::SliceComponent::EntityAncestorList ancestors; + sliceReference->GetInstanceEntityAncestry(entity->GetId(), ancestors); - // Populate slice push options. - // Address should start with the fully-addressable component Id to resolve within the target entity. - InstanceDataHierarchy::Address pushFieldAddress; - CalculateAndAdjustNodeAddress(*fieldNode, AddressRootType::RootAtEntity, pushFieldAddress); - if (!pushFieldAddress.empty()) + AZ_Error( + "PropertyEditor", !ancestors.empty(), "Entity \"%s\" belongs to a slice, but its source entity could not be located.", + entity->GetName().c_str()); + if (!ancestors.empty()) { - SliceUtilities::PopulateQuickPushMenu( - menu, - entity->GetId(), - pushFieldAddress, - SliceUtilities::QuickPushMenuOptions("Save field override", SliceUtilities::QuickPushMenuOverrideDisplayCount::ShowOverrideCountOnlyWhenMultiple)); + menu.addSeparator(); + + // Populate slice push options. + // Address should start with the fully-addressable component Id to resolve within the target entity. + InstanceDataHierarchy::Address pushFieldAddress; + CalculateAndAdjustNodeAddress(*fieldNode, AddressRootType::RootAtEntity, pushFieldAddress); + if (!pushFieldAddress.empty()) + { + SliceUtilities::PopulateQuickPushMenu( + menu, entity->GetId(), pushFieldAddress, + SliceUtilities::QuickPushMenuOptions( + "Save field override", + SliceUtilities::QuickPushMenuOverrideDisplayCount::ShowOverrideCountOnlyWhenMultiple)); + } } } - } - menu.addSeparator(); + menu.addSeparator(); - // by leaf node, we mean a visual leaf node in the property editor (ie, we do not have any visible children) - bool isLeafNode = !fieldNode->GetClassMetadata() || !fieldNode->GetClassMetadata()->m_container; + // by leaf node, we mean a visual leaf node in the property editor (ie, we do not have any visible children) + bool isLeafNode = !fieldNode->GetClassMetadata() || !fieldNode->GetClassMetadata()->m_container; - if (isLeafNode) - { - for (const InstanceDataNode& childNode : fieldNode->GetChildren()) + if (isLeafNode) { - if (HasAnyVisibleElements(childNode)) + for (const InstanceDataNode& childNode : fieldNode->GetChildren()) { - // If we have any visible children, we must not be a leaf node - isLeafNode = false; - break; + if (HasAnyVisibleElements(childNode)) + { + // If we have any visible children, we must not be a leaf node + isLeafNode = false; + break; + } } } - } #ifdef ENABLE_SLICE_EDITOR - // Show PreventOverride & HideProperty options - if (GetEntityDataPatchAddress(fieldNode, m_dataPatchAddressBuffer)) - { - AZ::DataPatch::Flags nodeFlags = rootSlice->GetEntityDataFlagsAtAddress(entity->GetId(), m_dataPatchAddressBuffer); + // Show PreventOverride & HideProperty options + if (GetEntityDataPatchAddress(fieldNode, m_dataPatchAddressBuffer)) + { + AZ::DataPatch::Flags nodeFlags = rootSlice->GetEntityDataFlagsAtAddress(entity->GetId(), m_dataPatchAddressBuffer); - if (nodeFlags & AZ::DataPatch::Flag::PreventOverrideSet) - { - QAction* PreventOverrideAction = menu.addAction(tr("Allow property override")); - PreventOverrideAction->setEnabled(isLeafNode); - connect(PreventOverrideAction, &QAction::triggered, this, [this, fieldNode] + if (nodeFlags & AZ::DataPatch::Flag::PreventOverrideSet) { - ContextMenuActionSetDataFlag(fieldNode, AZ::DataPatch::Flag::PreventOverrideSet, false); - InvalidatePropertyDisplay(Refresh_AttributesAndValues); + QAction* PreventOverrideAction = menu.addAction(tr("Allow property override")); + PreventOverrideAction->setEnabled(isLeafNode); + connect( + PreventOverrideAction, &QAction::triggered, this, + [this, fieldNode] + { + ContextMenuActionSetDataFlag(fieldNode, AZ::DataPatch::Flag::PreventOverrideSet, false); + InvalidatePropertyDisplay(Refresh_AttributesAndValues); + }); } - ); - } - else - { - QAction* PreventOverrideAction = menu.addAction(tr("Prevent property override")); - PreventOverrideAction->setEnabled(isLeafNode); - connect(PreventOverrideAction, &QAction::triggered, this, [this, fieldNode] + else { - ContextMenuActionSetDataFlag(fieldNode, AZ::DataPatch::Flag::PreventOverrideSet, true); - InvalidatePropertyDisplay(Refresh_AttributesAndValues); + QAction* PreventOverrideAction = menu.addAction(tr("Prevent property override")); + PreventOverrideAction->setEnabled(isLeafNode); + connect( + PreventOverrideAction, &QAction::triggered, this, + [this, fieldNode] + { + ContextMenuActionSetDataFlag(fieldNode, AZ::DataPatch::Flag::PreventOverrideSet, true); + InvalidatePropertyDisplay(Refresh_AttributesAndValues); + }); } - ); - } - if (nodeFlags & AZ::DataPatch::Flag::HidePropertySet) - { - QAction* HideProperyAction = menu.addAction(tr("Show property on instances")); - HideProperyAction->setEnabled(isLeafNode); - connect(HideProperyAction, &QAction::triggered, this, [this, fieldNode] + if (nodeFlags & AZ::DataPatch::Flag::HidePropertySet) { - ContextMenuActionSetDataFlag(fieldNode, AZ::DataPatch::Flag::HidePropertySet, false); - InvalidatePropertyDisplay(Refresh_AttributesAndValues); + QAction* HideProperyAction = menu.addAction(tr("Show property on instances")); + HideProperyAction->setEnabled(isLeafNode); + connect( + HideProperyAction, &QAction::triggered, this, + [this, fieldNode] + { + ContextMenuActionSetDataFlag(fieldNode, AZ::DataPatch::Flag::HidePropertySet, false); + InvalidatePropertyDisplay(Refresh_AttributesAndValues); + }); } - ); - } - else - { - QAction* HideProperyAction = menu.addAction(tr("Hide property on instances")); - HideProperyAction->setEnabled(isLeafNode); - connect(HideProperyAction, &QAction::triggered, this, [this, fieldNode] + else { - ContextMenuActionSetDataFlag(fieldNode, AZ::DataPatch::Flag::HidePropertySet, true); - InvalidatePropertyDisplay(Refresh_AttributesAndValues); + QAction* HideProperyAction = menu.addAction(tr("Hide property on instances")); + HideProperyAction->setEnabled(isLeafNode); + connect( + HideProperyAction, &QAction::triggered, this, + [this, fieldNode] + { + ContextMenuActionSetDataFlag(fieldNode, AZ::DataPatch::Flag::HidePropertySet, true); + InvalidatePropertyDisplay(Refresh_AttributesAndValues); + }); } - ); } - } #endif - if (sliceReference) - { - // This entity is referenced from a slice, so show property override options - bool hasChanges = fieldNode->HasChangesVersusComparison(false); - - if (!hasChanges && isLeafNode) + if (sliceReference) { - // Add an option to set the ForceOverride flag for this field - menu.setToolTipsVisible(true); - QAction* forceOverrideAction = menu.addAction(tr("Force property override")); - forceOverrideAction->setToolTip(tr("Prevents a property from inheriting from its source slice")); - connect(forceOverrideAction, &QAction::triggered, this, [this, fieldNode]() - { - ContextMenuActionSetDataFlag(fieldNode, AZ::DataPatch::Flag::ForceOverrideSet, true); - } - ); + // This entity is referenced from a slice, so show property override options + bool hasChanges = fieldNode->HasChangesVersusComparison(false); + + if (!hasChanges && isLeafNode) + { + // Add an option to set the ForceOverride flag for this field + menu.setToolTipsVisible(true); + QAction* forceOverrideAction = menu.addAction(tr("Force property override")); + forceOverrideAction->setToolTip(tr("Prevents a property from inheriting from its source slice")); + connect( + forceOverrideAction, &QAction::triggered, this, + [this, fieldNode]() + { + ContextMenuActionSetDataFlag(fieldNode, AZ::DataPatch::Flag::ForceOverrideSet, true); + }); + } + } + } + + m_reorderRowWidget = nullptr; + // Add move up/down actions if appropriate + auto componentEditorIterator = m_componentToEditorMap.find(componentInstance); + AZ_Assert(componentEditorIterator != m_componentToEditorMap.end(), "Unable to find a component editor for the given component"); + if (componentEditorIterator != m_componentToEditorMap.end()) + { + m_reorderRowWidgetEditor = componentEditorIterator->second; + PropertyRowWidget* widget = componentEditorIterator->second->GetPropertyEditor()->GetWidgetFromNode(fieldNode); + if (widget->CanBeReordered()) + { + m_reorderRowWidget = widget; + SetRowWidgetHighlighted(widget); + + QAction* moveUpAction = menu.addAction(tr("Move %1 Up").arg(widget->GetNameLabel()->text())); + moveUpAction->setEnabled(false); + moveUpAction->setData(kPropertyEditorMenuActionMoveUp); + + if (widget->CanMoveUp()) + { + moveUpAction->setEnabled(true); + connect( + moveUpAction, &QAction::triggered, this, + [this, widget] + { + ContextMenuActionMoveItemUp(m_reorderRowWidgetEditor, widget); + }); + } + + QAction* moveDownAction = menu.addAction(tr("Move %1 Down").arg(widget->GetNameLabel()->text())); + moveDownAction->setEnabled(false); + moveDownAction->setData(kPropertyEditorMenuActionMoveDown); + if (widget->CanMoveDown()) + { + moveDownAction->setEnabled(true); + connect( + moveDownAction, &QAction::triggered, this, + [this, widget] + { + ContextMenuActionMoveItemDown(m_reorderRowWidgetEditor, widget); + }); + } + + menu.addSeparator(); } } } @@ -2380,6 +2626,98 @@ namespace AzToolsFramework } } + void EntityPropertyEditor::BeginMoveRowWidgetFade() + { + // Fade out the highlights and indicator bar for two seconds before moving. + m_moveFadeSecondsRemaining = MoveFadeSeconds; + m_currentReorderState = EntityPropertyEditor::ReorderState::MenuOperationInProgress; + AZ::TickBus::Handler::BusConnect(); + } + + void EntityPropertyEditor::HighlightMovedRowWidget() + { + if (m_currentReorderState != ReorderState::WaitForRedraw) + { + return; + } + UpdateOverlay(); + + m_currentReorderState = ReorderState::HighlightMovedRow; + m_moveFadeSecondsRemaining = MoveFadeSeconds; + + AZ::TickBus::Handler::BusConnect(); + m_overlay->setVisible(true); + } + + void EntityPropertyEditor::OnTick(float deltaTime, AZ::ScriptTimePoint /*time*/) + { + m_moveFadeSecondsRemaining -= deltaTime; + m_overlay->setVisible(true); + if (m_moveFadeSecondsRemaining <= 0.0f) + { + m_moveFadeSecondsRemaining = 0.0f; + + if (m_currentReorderState == ReorderState::MenuOperationInProgress) + { + m_reorderRowWidgetEditor->GetPropertyEditor()->MoveNodeToIndex(m_nodeToMove, m_indexMapOfMovedRow[0]); + + // Ensure the highlight gets drawn once the RPE is updated. + m_currentReorderState = ReorderState::WaitForRedraw; + AZ::TickBus::Handler::BusDisconnect(); + ScrollToNewComponent(); + } + else + { + m_currentReorderState = ReorderState::Inactive; + AZ::TickBus::Handler::BusDisconnect(); + m_overlay->setVisible(false); + } + } + + // Force a repaint to show the fade. + repaint(0, 0, -1, -1); + } + + void EntityPropertyEditor::GenerateRowWidgetIndexMapToChildIndex(PropertyRowWidget* parent, int destIndex) + { + m_indexMapOfMovedRow.clear(); + m_indexMapOfMovedRow.push_back(destIndex); + + while (parent) + { + int index = parent->GetIndexInParent(); + if (index < 0) + { + // Top level widget. + break; + } + m_indexMapOfMovedRow.push_back(parent->GetIndexInParent()); + parent = parent->GetParentRow(); + } + } + + void EntityPropertyEditor::ContextMenuActionMoveItemUp(ComponentEditor* componentEditor, PropertyRowWidget* rowWidget) + { + // After the RPE is rebuilt, there'll be no way to work out which is the moved RowWidget. + // Generate a map of the child indices up to the root. + PropertyRowWidget* parent = rowWidget->GetParentRow(); + GenerateRowWidgetIndexMapToChildIndex(parent, rowWidget->GetIndexInParent() - 1); + + m_reorderRowWidgetEditor = componentEditor; + m_nodeToMove = rowWidget->GetNode(); + BeginMoveRowWidgetFade(); + } + + void EntityPropertyEditor::ContextMenuActionMoveItemDown(ComponentEditor* componentEditor, PropertyRowWidget* rowWidget) + { + PropertyRowWidget* parent = rowWidget->GetParentRow(); + GenerateRowWidgetIndexMapToChildIndex(parent, rowWidget->GetIndexInParent() + 1); + + m_reorderRowWidgetEditor = componentEditor; + m_nodeToMove = rowWidget->GetNode(); + BeginMoveRowWidgetFade(); + } + void EntityPropertyEditor::CalculateAndAdjustNodeAddress(const InstanceDataNode& componentFieldNode, AddressRootType rootType, InstanceDataNode::Address& outAddress) const { outAddress = componentFieldNode.ComputeAddress(); @@ -2763,9 +3101,7 @@ namespace AzToolsFramework if (!menu.actions().empty()) { - m_isShowingContextMenu = true; menu.exec(position); - m_isShowingContextMenu = false; } } @@ -3463,6 +3799,76 @@ namespace AzToolsFramework return this == widget || isAncestorOf(widget); } + AZ::u32 EntityPropertyEditor::GetHeightOfRowAndVisibleChildren(const PropertyRowWidget* row) const + { + if (!row->isVisible()) + { + return 0; + } + + QRect rect = QRect(row->mapToGlobal(row->rect().topLeft()), row->mapToGlobal(row->rect().bottomRight())); + + AZ::u32 height = rect.height() + 1; + + for (AZ::u32 childIndex = 0; childIndex < row->GetChildRowCount(); childIndex++) + { + PropertyRowWidget* childRow = row->GetChildRowByIndex(childIndex); + if (childRow->isVisible()) + { + height += GetHeightOfRowAndVisibleChildren(childRow); + } + } + + return height; + } + + QRect EntityPropertyEditor::GetWidgetAndVisibleChildrenGlobalRect(const PropertyRowWidget* widget) const + { + QRect rect = QRect(widget->mapToGlobal(widget->rect().topLeft()), widget->mapToGlobal(widget->rect().bottomRight())); + rect.setHeight(GetHeightOfRowAndVisibleChildren(widget)); + + return rect; + } + + PropertyRowWidget* EntityPropertyEditor::GetRowWidgetAtSameLevelAfter(PropertyRowWidget* widget) const + { + PropertyRowWidget* parent = widget->GetParentRow(); + + bool found = false; + for (PropertyRowWidget* child : parent->GetChildrenRows()) + { + if (found) + { + return child; + } + + if (child == widget) + { + found = true; + } + } + + return nullptr; + } + + PropertyRowWidget* EntityPropertyEditor::GetRowWidgetAtSameLevelBefore(PropertyRowWidget* widget) const + { + PropertyRowWidget* parent = widget->GetParentRow(); + + PropertyRowWidget* previous = nullptr; + for (PropertyRowWidget* child : parent->GetChildrenRows()) + { + if (child == widget) + { + return previous; + } + + previous = child; + } + + return nullptr; + } + QRect EntityPropertyEditor::GetWidgetGlobalRect(const QWidget* widget) const { return QRect( @@ -3757,6 +4163,8 @@ namespace AzToolsFramework m_shouldScrollToNewComponents = false; m_shouldScrollToNewComponentsQueued = false; m_newComponentId.reset(); + + HighlightMovedRowWidget(); } void EntityPropertyEditor::QueueScrollToNewComponent() @@ -3909,9 +4317,64 @@ namespace AzToolsFramework event->accept(); } + bool EntityPropertyEditor::HandleMenuEvent(QObject* /*object*/, QEvent* event) + { + QMenu* menu = qobject_cast(QApplication::activePopupWidget()); + if (!menu) + { + return false; + } + + PropertyRowWidget* lastReorderDropTarget = m_reorderDropTarget; + + switch (event->type()) + { + case QEvent::Leave: + m_reorderDropTarget = nullptr; + break; + case QEvent::Enter: + // Drop through. + case QEvent::MouseMove: + QMouseEvent* originalMouseEvent = static_cast(event); + QAction* action = menu->actionAt(originalMouseEvent->pos()); + if (!action) + { + m_reorderDropTarget = nullptr; + break; + } + + if (action->data() == kPropertyEditorMenuActionMoveUp) + { + m_reorderDropTarget = GetRowWidgetAtSameLevelBefore(m_reorderRowWidget); + + m_reorderDropArea = EntityPropertyEditor::DropArea::Above; + } + else if (action->data() == kPropertyEditorMenuActionMoveDown) + { + m_reorderDropTarget = GetRowWidgetAtSameLevelAfter(m_reorderRowWidget); + + if (m_reorderDropTarget) + { + m_reorderDropArea = EntityPropertyEditor::DropArea::Below; + } + } + + break; + } + + if (lastReorderDropTarget != m_reorderDropTarget) + { + // Force a redraw as the menu is preventing automatic updates. + repaint(0, 0, -1, -1); + } + + return false; + } + //overridden to intercept application level mouse events for component editor selection bool EntityPropertyEditor::eventFilter(QObject* object, QEvent* event) { + HandleMenuEvent(object, event); HandleSelectionEvents(object, event); return false; } @@ -3919,11 +4382,23 @@ namespace AzToolsFramework void EntityPropertyEditor::mousePressEvent(QMouseEvent* event) { ResetDrag(event); + + PropertyRowWidget* rowWidget = FindPropertyRowWidgetAt(event->globalPos()); + if (rowWidget && rowWidget->CanBeReordered() && event->buttons() & Qt::LeftButton) + { + QApplication::setOverrideCursor(m_dragCursor); + } } void EntityPropertyEditor::mouseReleaseEvent(QMouseEvent* event) { ResetDrag(event); + + Qt::MouseButtons realButtons = QApplication::mouseButtons(); + if (QApplication::overrideCursor() && !(event->buttons() & Qt::LeftButton)) + { + QApplication::restoreOverrideCursor(); + } } void EntityPropertyEditor::mouseMoveEvent(QMouseEvent* event) @@ -3963,6 +4438,21 @@ namespace AzToolsFramework void EntityPropertyEditor::dropEvent(QDropEvent* event) { HandleDrop(event); + + if (QApplication::overrideCursor()) + { + QApplication::restoreOverrideCursor(); + } + } + + void EntityPropertyEditor::DragStopped() + { + if (QApplication::overrideCursor()) + { + QApplication::restoreOverrideCursor(); + } + + EndRowWidgetReorder(); } bool EntityPropertyEditor::HandleSelectionEvents(QObject* object, QEvent* event) @@ -4319,11 +4809,110 @@ namespace AzToolsFramework return true; } + bool EntityPropertyEditor::FindAllowedRowWidgetReorderDropTarget(const QPoint& globalPos) + { + const QRect globalRect(globalPos, globalPos); + + AZ_Assert(m_reorderRowWidgetEditor, "Missing editor for row widget drag."); + + AzToolsFramework::ReflectedPropertyEditor::WidgetList widgets = m_reorderRowWidgetEditor->GetPropertyEditor()->GetWidgets(); + for (auto widgetPair : widgets) + { + PropertyRowWidget* widget = widgetPair.second; + if (!widget) + { + continue; + } + + if (DoesIntersectWidget(globalRect, reinterpret_cast(widget))) + { + if (widget->CanBeReordered() && widget->GetParentRow() == m_reorderRowWidget->GetParentRow()) + { + m_reorderDropTarget = widget; + + QRect widgetRect = GetWidgetAndVisibleChildrenGlobalRect(widget); + if (globalPos.y() < widgetRect.center().y()) + { + m_reorderDropArea = EntityPropertyEditor::DropArea::Above; + } + else + { + m_reorderDropArea = EntityPropertyEditor::DropArea::Below; + } + + return true; + } + + // We're hovering over a child of a reorderable ancestor, use the ancestor as the drop target. + PropertyRowWidget* parent = widget->GetParentRow(); + while (parent) + { + if (parent->CanBeReordered() && parent->GetParentRow() == m_reorderRowWidget->GetParentRow()) + { + m_reorderDropTarget = parent; + + QRect widgetRect = GetWidgetAndVisibleChildrenGlobalRect(parent); + if (globalPos.y() < widgetRect.center().y()) + { + m_reorderDropArea = EntityPropertyEditor::DropArea::Above; + } + else + { + m_reorderDropArea = EntityPropertyEditor::DropArea::Below; + } + + return true; + } + parent = parent->GetParentRow(); + } + } + } + + return false; + } + + bool EntityPropertyEditor::UpdateRowWidgetDrag(const QPoint& localPos, Qt::MouseButtons mouseButtons, const QMimeData* /*mimeData*/) + { + const QPoint globalPos(mapToGlobal(localPos)); + const QRect globalRect(globalPos, globalPos); + + if (!m_reorderRowWidget) + { + return false; + } + + if (m_reorderDropTarget) + { + m_reorderDropTarget = nullptr; + } + + UpdateOverlay(); + + // additional checks since handling is done in event filter + if ((mouseButtons & Qt::LeftButton) && DoesIntersectWidget(globalRect, this)) + { + FindAllowedRowWidgetReorderDropTarget(globalPos); + { + UpdateOverlay(); + return true; + } + } + return false; + } + bool EntityPropertyEditor::UpdateDrag(const QPoint& localPos, Qt::MouseButtons mouseButtons, const QMimeData* mimeData) { const QPoint globalPos(mapToGlobal(localPos)); const QRect globalRect(globalPos, globalPos); + if (m_reorderRowWidget) + { + UpdateRowWidgetDrag(localPos, mouseButtons, mimeData); + QueueAutoScroll(); + UpdateOverlay(); + return true; + } + //reset drop indicators for (auto componentEditor : m_componentEditors) { @@ -4357,6 +4946,28 @@ namespace AzToolsFramework return false; } + PropertyRowWidget* EntityPropertyEditor::FindPropertyRowWidgetAt(QPoint globalPos) + { + const QRect globalRect(globalPos, globalPos); + + const bool dragSelected = DoesIntersectSelectedComponentEditor(globalRect); + const auto& componentEditors = dragSelected ? GetSelectedComponentEditors() : GetIntersectingComponentEditors(globalRect); + + for (auto componentEditor : componentEditors) + { + AzToolsFramework::ReflectedPropertyEditor::WidgetList widgets = componentEditor->GetPropertyEditor()->GetWidgets(); + for (auto& [dataNode, rowWidget] : widgets) + { + if (DoesIntersectWidget(globalRect, reinterpret_cast(rowWidget)) && rowWidget->CanBeReordered()) + { + return rowWidget; + } + } + } + + return nullptr; + } + bool EntityPropertyEditor::StartDrag(QMouseEvent* event) { // do not initiate a drag if property editor is disabled @@ -4402,7 +5013,27 @@ namespace AzToolsFramework if (!intersectsHeader) { - return false; + for (auto componentEditor : componentEditors) + { + AzToolsFramework::ReflectedPropertyEditor::WidgetList widgets = componentEditor->GetPropertyEditor()->GetWidgets(); + for (AZStd::pair w : widgets) + { + if (w.second) + { + if (DoesIntersectWidget(dragRect, reinterpret_cast(w.second)) && w.second->CanBeReordered()) + { + m_currentReorderState = EntityPropertyEditor::ReorderState::DraggingRowWidget; + m_reorderRowWidget = w.second; + m_reorderRowWidgetEditor = componentEditor; + if (m_reorderDropTarget) + { + m_reorderDropTarget = nullptr; + } + break; + } + } + } + } } m_dragStarted = true; @@ -4412,105 +5043,166 @@ namespace AzToolsFramework QRect dragImageRect; - AZStd::vector componentEditorIndices; - componentEditorIndices.reserve(componentEditors.size()); - for (auto componentEditor : componentEditors) + if (m_reorderRowWidget) { - //compute the drag image size - if (componentEditorIndices.empty()) - { - dragImageRect = componentEditor->rect(); - } - else - { - dragImageRect.setHeight(dragImageRect.height() + componentEditor->rect().height()); - } + // We're dragging a PropertyRowWidget, grab the image from that. + mimeData->setData(kComponentEditorRowWidgetType, QByteArray()); - //add component editor index to drag data - auto componentEditorIndex = GetComponentEditorIndex(componentEditor); - if (componentEditorIndex >= 0) - { - componentEditorIndices.push_back(GetComponentEditorIndex(componentEditor)); - } + drag->setMimeData(mimeData); + drag->setPixmap(m_reorderRowWidget->createDragImage( + QColor("#8E863E"), QColor("#EAECAA"), 0.5f, PropertyRowWidget::DragImageType::SingleRow)); + drag->setHotSpot(m_dragStartPosition - GetWidgetGlobalRect(m_reorderRowWidget).topLeft()); + drag->setDragCursor(m_dragIcon.pixmap(32), Qt::DropAction::MoveAction); + // Ensure we can tidy up if the drop happens elsewhere. + connect(drag, &QObject::destroyed, this, &EntityPropertyEditor::DragStopped); + drag->exec(Qt::MoveAction, Qt::MoveAction); } - - //build image from dragged editor UI - QImage dragImage(dragImageRect.size(), QImage::Format_ARGB32_Premultiplied); - QPainter painter(&dragImage); - painter.setCompositionMode(QPainter::CompositionMode_Source); - painter.fillRect(dragImageRect, Qt::transparent); - painter.setCompositionMode(QPainter::CompositionMode_SourceOver); - painter.setOpacity(0.5f); - - //render a vertical stack of component editors, may change to render just the headers - QPoint dragImageOffset(0, 0); - for (AZ::s32 index : componentEditorIndices) + else { - auto componentEditor = GetComponentEditorsFromIndex(index); - if (componentEditor) + AZStd::vector componentEditorIndices; + componentEditorIndices.reserve(componentEditors.size()); + for (auto componentEditor : componentEditors) { - if (DoesIntersectWidget(dragRect, componentEditor)) + // compute the drag image size + if (componentEditorIndices.empty()) { - //offset drag image from the drag start position - drag->setHotSpot(dragImageOffset + (m_dragStartPosition - GetWidgetGlobalRect(componentEditor).topLeft())); + dragImageRect = componentEditor->rect(); + } + else + { + dragImageRect.setHeight(dragImageRect.height() + componentEditor->rect().height()); } - //render the component editor to the drag image - componentEditor->render(&painter, dragImageOffset); - - //update the render offset by the component editor height - dragImageOffset.setY(dragImageOffset.y() + componentEditor->rect().height()); + // add component editor index to drag data + auto componentEditorIndex = GetComponentEditorIndex(componentEditor); + if (componentEditorIndex >= 0) + { + componentEditorIndices.push_back(GetComponentEditorIndex(componentEditor)); + } } - } - painter.end(); - //mark dragged components after drag initiated to draw indicators - for (AZ::s32 index : componentEditorIndices) - { - auto componentEditor = GetComponentEditorsFromIndex(index); - if (componentEditor) + // build image from dragged editor UI + QImage dragImage(dragImageRect.size(), QImage::Format_ARGB32_Premultiplied); + QPainter painter(&dragImage); + painter.setCompositionMode(QPainter::CompositionMode_Source); + painter.fillRect(dragImageRect, Qt::transparent); + painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + painter.setOpacity(0.5f); + + // render a vertical stack of component editors, may change to render just the headers + QPoint dragImageOffset(0, 0); + for (AZ::s32 index : componentEditorIndices) { - componentEditor->SetDragged(true); + auto componentEditor = GetComponentEditorsFromIndex(index); + if (componentEditor) + { + if (DoesIntersectWidget(dragRect, componentEditor)) + { + // offset drag image from the drag start position + drag->setHotSpot(dragImageOffset + (m_dragStartPosition - GetWidgetGlobalRect(componentEditor).topLeft())); + } + + // render the component editor to the drag image + componentEditor->render(&painter, dragImageOffset); + + // update the render offset by the component editor height + dragImageOffset.setY(dragImageOffset.y() + componentEditor->rect().height()); + } } - } - UpdateOverlay(); + painter.end(); - //encode component editor indices as internal drag data - mimeData->setData( - kComponentEditorIndexMimeType, - QByteArray(reinterpret_cast(componentEditorIndices.data()), static_cast(componentEditorIndices.size() * sizeof(AZ::s32)))); - - drag->setMimeData(mimeData); - drag->setPixmap(QPixmap::fromImage(dragImage)); - drag->exec(Qt::MoveAction, Qt::MoveAction); - - //mark dragged components after drag completed to stop drawing indicators - for (AZ::s32 index : componentEditorIndices) - { - auto componentEditor = GetComponentEditorsFromIndex(index); - if (componentEditor) + // mark dragged components after drag initiated to draw indicators + for (AZ::s32 index : componentEditorIndices) { - componentEditor->SetDragged(false); + auto componentEditor = GetComponentEditorsFromIndex(index); + if (componentEditor) + { + componentEditor->SetDragged(true); + } + } + UpdateOverlay(); + + // encode component editor indices as internal drag data + mimeData->setData( + kComponentEditorIndexMimeType, + QByteArray( + reinterpret_cast(componentEditorIndices.data()), + static_cast(componentEditorIndices.size() * sizeof(AZ::s32)))); + + drag->setMimeData(mimeData); + drag->setPixmap(QPixmap::fromImage(dragImage)); + drag->exec(Qt::MoveAction, Qt::MoveAction); + + // mark dragged components after drag completed to stop drawing indicators + for (AZ::s32 index : componentEditorIndices) + { + auto componentEditor = GetComponentEditorsFromIndex(index); + if (componentEditor) + { + componentEditor->SetDragged(false); + } } } + UpdateOverlay(); return true; } + void EntityPropertyEditor::SetRowWidgetHighlighted(PropertyRowWidget* rowWidget) + { + m_reorderRowWidget = rowWidget; + m_reorderRowImage = rowWidget->createDragImage( + QColor("#8E863E"), QColor("#EAECAA"), 0.5f, PropertyRowWidget::DragImageType::IncludeVisibleChildren); + } + + void EntityPropertyEditor::EndRowWidgetReorder() + { + m_reorderDropTarget = nullptr; + m_reorderRowWidget = nullptr; + m_reorderDropTarget = nullptr; + m_currentReorderState = EntityPropertyEditor::ReorderState::Inactive; + m_overlay->setVisible(false); + } + bool EntityPropertyEditor::HandleDrop(QDropEvent* event) { const QPoint globalPos(mapToGlobal(event->pos())); const QMimeData* mimeData = event->mimeData(); - if (IsDropAllowed(mimeData, globalPos)) + + if (m_currentReorderState == EntityPropertyEditor::ReorderState::DraggingRowWidget) { - //handle drop for supported mime types - HandleDropForComponentTypes(event); - HandleDropForComponentAssets(event); - HandleDropForAssetBrowserEntries(event); - HandleDropForComponentReorder(event); + if (FindAllowedRowWidgetReorderDropTarget(globalPos)) + { + if (m_reorderDropArea == EntityPropertyEditor::DropArea::Above) + { + m_reorderRowWidgetEditor->GetPropertyEditor()->MoveNodeBefore( + m_reorderRowWidget->GetNode(), m_reorderDropTarget->GetNode()); + } + else + { + m_reorderRowWidgetEditor->GetPropertyEditor()->MoveNodeAfter( + m_reorderRowWidget->GetNode(), m_reorderDropTarget->GetNode()); + } + } + event->acceptProposedAction(); - return true; + + EndRowWidgetReorder(); } + else + { + if (IsDropAllowed(mimeData, globalPos)) + { + // handle drop for supported mime types + HandleDropForComponentTypes(event); + HandleDropForComponentAssets(event); + HandleDropForAssetBrowserEntries(event); + HandleDropForComponentReorder(event); + event->acceptProposedAction(); + return true; + } + } + return false; } @@ -5036,6 +5728,69 @@ namespace AzToolsFramework componentEditor->ActiveComponentModeChanged(componentType); } } + + EntityPropertyEditor::ReorderState EntityPropertyEditor::GetReorderState() const + { + return m_currentReorderState; + } + + ComponentEditor* EntityPropertyEditor::GetEditorForCurrentReorderRowWidget() const + { + return m_reorderRowWidgetEditor; + } + + PropertyRowWidget* EntityPropertyEditor::GetReorderRowWidget() const + { + return m_reorderRowWidget; + } + + PropertyRowWidget* EntityPropertyEditor::GetReorderDropTarget() const + { + return m_reorderDropTarget; + } + + EntityPropertyEditor::DropArea EntityPropertyEditor::GetReorderDropArea() const + { + return m_reorderDropArea; + } + + QPixmap EntityPropertyEditor::GetReorderRowWidgetImage() const + { + return m_reorderRowImage; + } + + float EntityPropertyEditor::GetMoveIndicatorAlpha() const + { + if (m_currentReorderState != ReorderState::MenuOperationInProgress) + { + return 1.0f; + } + + return m_moveFadeSecondsRemaining / MoveFadeSeconds; + } + + PropertyRowWidget* EntityPropertyEditor::GetRowToHighlight() + { + // Use the pregenerated map to find the RowWidget that's in the new position. + QSet rowWidgets = m_reorderRowWidgetEditor->GetPropertyEditor()->GetTopLevelWidgets(); + if (rowWidgets.isEmpty()) + { + return nullptr; + } + + PropertyRowWidget* highlightRow = *rowWidgets.begin(); + + int mapIndex = static_cast(m_indexMapOfMovedRow.size() - 1); + + while (mapIndex >= 0) + { + int mapEntry = m_indexMapOfMovedRow[mapIndex]; + highlightRow = highlightRow->GetChildrenRows()[mapEntry]; + mapIndex--; + } + + return highlightRow; + } } StatusComboBox::StatusComboBox(QWidget* parent) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx index 166d4c4392..3ff69f80e0 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -110,6 +111,7 @@ namespace AzToolsFramework , public EditorInspectorComponentNotificationBus::MultiHandler , private AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus::Handler , public AZ::EntitySystemBus::Handler + , public AZ::TickBus::Handler , private EditorWindowUIRequestBus::Handler { Q_OBJECT; @@ -117,6 +119,23 @@ namespace AzToolsFramework AZ_CLASS_ALLOCATOR(EntityPropertyEditor, AZ::SystemAllocator, 0) + enum class ReorderState + { + Inactive, // No row widget reordering operation is in progress. + DraggingComponent, // User is dragging a component editor. + DraggingRowWidget, // User is dragging a row widget around. + UsingMenu, // User has the context menu open and may hover over a move up/down operation. + MenuOperationInProgress, // User has selected a move/up down menu item. + WaitForRedraw, // Wait for rebuild of RPE. + HighlightMovedRow // User has moved a row, highlight the new position. + }; + + enum class DropArea + { + Above, + Below + }; + EntityPropertyEditor(QWidget* pParent = NULL, Qt::WindowFlags flags = Qt::WindowFlags(), bool isLevelEntityEditor = false); virtual ~EntityPropertyEditor(); @@ -151,6 +170,16 @@ namespace AzToolsFramework bool IsLockedToSpecificEntities() const { return !m_overrideSelectedEntityIds.empty(); } static bool AreComponentsCopyable(const AZ::Entity::ComponentArrayType& components, const ComponentFilter& filter); + + ReorderState GetReorderState() const; + ComponentEditor* GetEditorForCurrentReorderRowWidget() const; + PropertyRowWidget* GetReorderRowWidget() const; + PropertyRowWidget* GetReorderDropTarget() const; + DropArea GetReorderDropArea() const; + QPixmap GetReorderRowWidgetImage() const; + float GetMoveIndicatorAlpha() const; + PropertyRowWidget* GetRowToHighlight(); + Q_SIGNALS: void SelectedEntityNameChanged(const AZ::EntityId& entityId, const AZStd::string& name); @@ -211,6 +240,9 @@ namespace AzToolsFramework void GetSelectedEntities(EntityIdList& selectedEntityIds) override; void SetNewComponentId(AZ::ComponentId componentId) override; + // TickBus + void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; + // EditorWindowRequestBus overrides void SetEditorUiEnabled(bool enable) override; @@ -253,6 +285,10 @@ namespace AzToolsFramework void ContextMenuActionPullFieldData(AZ::Component* parentComponent, InstanceDataNode* fieldNode); void ContextMenuActionSetDataFlag(InstanceDataNode* node, AZ::DataPatch::Flag flag, bool additive); + void GenerateRowWidgetIndexMapToChildIndex(PropertyRowWidget* parent, int destIndex); + void ContextMenuActionMoveItemUp(ComponentEditor* componentEditor, PropertyRowWidget* rowWidget); + void ContextMenuActionMoveItemDown(ComponentEditor* componentEditor, PropertyRowWidget* rowWidget); + /// Given an InstanceDataNode, calculate a DataPatch address relative to the entity. /// @return true if successful. bool GetEntityDataPatchAddress(const InstanceDataNode* componentFieldNode, AZ::DataPatch::AddressType& dataPatchAddressOut, AZ::EntityId* entityIdOut = nullptr) const; @@ -341,8 +377,6 @@ namespace AzToolsFramework QAction* m_actionToMoveComponentsBottom = nullptr; QAction* m_resetToSliceAction = nullptr; - bool m_isShowingContextMenu = false; - void CreateActions(); void UpdateActions(); @@ -390,6 +424,10 @@ namespace AzToolsFramework void ResetToSlice(); bool DoesOwnFocus() const; + AZ::u32 GetHeightOfRowAndVisibleChildren(const PropertyRowWidget* row) const; + QRect GetWidgetAndVisibleChildrenGlobalRect(const PropertyRowWidget* widget) const; + PropertyRowWidget* GetRowWidgetAtSameLevelAfter(PropertyRowWidget* widget) const; + PropertyRowWidget* GetRowWidgetAtSameLevelBefore(PropertyRowWidget* widget) const; QRect GetWidgetGlobalRect(const QWidget* widget) const; bool DoesIntersectWidget(const QRect& globalRect, const QWidget* widget) const; bool DoesIntersectSelectedComponentEditor(const QRect& globalRect) const; @@ -445,6 +483,8 @@ namespace AzToolsFramework bool HandleSelectionEvents(QObject* object, QEvent* event); bool m_selectionEventAccepted; + bool HandleMenuEvent(QObject* object, QEvent* event); + // drag and drop events QRect GetInflatedRectFromPoint(const QPoint& point, int radius) const; bool GetComponentsAtDropEventPosition(QDropEvent* event, AZ::Entity::ComponentArrayType& targetComponents); @@ -458,8 +498,12 @@ namespace AzToolsFramework ComponentEditor* GetReorderDropTarget(const QRect& globalRect) const; bool ResetDrag(QMouseEvent* event); + bool FindAllowedRowWidgetReorderDropTarget(const QPoint& globalPos); + bool UpdateRowWidgetDrag(const QPoint& localPos, Qt::MouseButtons mouseButtons, const QMimeData* mimeData); + PropertyRowWidget* FindPropertyRowWidgetAt(QPoint globalPos); bool UpdateDrag(const QPoint& localPos, Qt::MouseButtons mouseButtons, const QMimeData* mimeData); bool StartDrag(QMouseEvent* event); + void EndRowWidgetReorder(); bool HandleDrop(QDropEvent* event); bool HandleDropForComponentTypes(QDropEvent* event); bool HandleDropForComponentAssets(QDropEvent* event); @@ -468,6 +512,8 @@ namespace AzToolsFramework bool CanDropForComponentTypes(const QMimeData* mimeData) const; bool CanDropForComponentAssets(const QMimeData* mimeData) const; bool CanDropForAssetBrowserEntries(const QMimeData* mimeData) const; + void SetRowWidgetHighlighted(PropertyRowWidget* rowWidget); + AZStd::vector ExtractComponentEditorIndicesFromMimeData(const QMimeData* mimeData) const; ComponentEditorVector GetComponentEditorsFromIndices(const AZStd::vector& indices) const; ComponentEditor* GetComponentEditorsFromIndex(const AZ::s32 index) const; @@ -559,6 +605,8 @@ namespace AzToolsFramework QIcon m_emptyIcon; QIcon m_clearIcon; + QIcon m_dragIcon; + QCursor m_dragCursor; QStandardItem* m_comboItems[StatusItems]; EntityIdSet m_overrideSelectedEntityIds; @@ -566,6 +614,19 @@ namespace AzToolsFramework Prefab::PrefabPublicInterface* m_prefabPublicInterface = nullptr; bool m_prefabsAreEnabled = false; + // Reordering row widgets within the RPE. + static constexpr float MoveFadeSeconds = 0.5f; + + ReorderState m_currentReorderState = ReorderState::Inactive; + ComponentEditor* m_reorderRowWidgetEditor = nullptr; + InstanceDataNode* m_nodeToMove = nullptr; + PropertyRowWidget* m_reorderRowWidget = nullptr; + PropertyRowWidget* m_reorderDropTarget = nullptr; + DropArea m_reorderDropArea = DropArea::Above; + QPixmap m_reorderRowImage; + float m_moveFadeSecondsRemaining; + AZStd::vector m_indexMapOfMovedRow; + // When m_initiatingPropertyChangeNotification is set to true, it means this EntityPropertyEditor is // broadcasting a change to all listeners about a property change for a given entity. This is needed // so that we don't update the values twice for this inspector @@ -573,6 +634,9 @@ namespace AzToolsFramework void ConnectToEntityBuses(const AZ::EntityId& entityId); void DisconnectFromEntityBuses(const AZ::EntityId& entityId); + void BeginMoveRowWidgetFade(); + void HighlightMovedRowWidget(); + //! Stores a component id to be focused on next time the UI updates. AZStd::optional m_newComponentId; @@ -594,6 +658,8 @@ namespace AzToolsFramework bool SelectedEntitiesAreFromSameSourceSliceEntity() const; + void DragStopped(); + AZ::Entity* GetSelectedEntityById(AZ::EntityId& entityId) const; }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp index 05c04872e3..c3da1e69b0 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp @@ -368,10 +368,15 @@ namespace AzToolsFramework delete m_containerAddButton; } + this->unsetCursor(); + if ((m_parentRow) && (m_parentRow->IsContainerEditable())) { if (!m_elementRemoveButton) { + QIcon icon = QIcon(QStringLiteral(":/Cursors/Grab_release.svg")); + this->setCursor(QCursor(icon.pixmap(16), 5, 2)); + static QIcon s_iconRemove(QStringLiteral(":/stylesheet/img/UI20/delete-16.svg")); m_elementRemoveButton = new QToolButton(this); m_elementRemoveButton->setAutoRaise(true); @@ -570,7 +575,12 @@ namespace AzToolsFramework AZ_Assert(m_selectionEnabled, "Property is not selectable"); m_isSelected = selected; m_nameLabel->setProperty("selected", selected); - } + } + + bool PropertyRowWidget::GetSelected() + { + return m_isSelected; + } void PropertyRowWidget::SetSelectionEnabled(bool selectionEnabled) { @@ -1395,6 +1405,21 @@ namespace AzToolsFramework return !m_childrenRows.empty(); } + AZ::u32 PropertyRowWidget::GetChildRowCount() const + { + return static_cast(m_childrenRows.size()); + } + + PropertyRowWidget* PropertyRowWidget::GetChildRowByIndex(AZ::u32 index) const + { + if (index >= m_childrenRows.size()) + { + return nullptr; + } + + return m_childrenRows[index]; + } + bool PropertyRowWidget::ShouldPreValidatePropertyChange() const { return (m_changeValidators.size() > 0); @@ -1722,6 +1747,162 @@ namespace AzToolsFramework return m_parentRow->CanChildrenBeReordered(); } + + int PropertyRowWidget::GetIndexInParent() const + { + if (!GetParentRow()) + { + return -1; + } + + for (int index = 0; index < GetParentRow()->GetChildRowCount(); index++) + { + if (GetParentRow()->GetChildrenRows()[index] == this) + { + return index; + } + } + + return -1; + } + + bool PropertyRowWidget::CanMoveUp() const + { + if (!CanBeReordered()) + { + return false; + } + + return this != m_parentRow->GetChildRowByIndex(0); + } + + bool PropertyRowWidget::CanMoveDown() const + { + if (!CanBeReordered()) + { + return false; + } + + AZ::u32 numChildrenOfParent = m_parentRow->GetChildRowCount(); + + return this != m_parentRow->GetChildRowByIndex(numChildrenOfParent - 1); + } + + int PropertyRowWidget::GetContainingEditorFrameWidth() + { + QWidget* parent = parentWidget(); + + // Find the first ancestor that can be cast to a QFrame, this will be the RPE. + while (!qobject_cast(parent)) + { + parent = parent->parentWidget(); + } + + if (!parent) + { + return 0; + } + + // The parent of the RPE is the size we want. + parent = parent->parentWidget(); + + return parent->rect().width(); + } + + int PropertyRowWidget::GetHeightOfRowAndVisibleChildren() + { + int height = rect().height(); + + if (!GetChildRowCount() || !IsExpanded()) + { + return height; + } + + for (auto childRow : GetChildrenRows()) + { + height += childRow->GetHeightOfRowAndVisibleChildren(); + } + + return height; + } + + int PropertyRowWidget::DrawDragImageAndVisibleChildrenInto(QPainter& painter, int xpos, int ypos) + { + // Render our image into the given painter. + int ystart = ypos; + + render(&painter, QPoint(xpos, ypos)); + + if (!GetChildRowCount() || !IsExpanded()) + { + return rect().height(); + } + + ypos += rect().height(); + + // Recursively draw any children. + for (auto childRow : GetChildrenRows()) + { + ypos += childRow->DrawDragImageAndVisibleChildrenInto(painter, xpos, ypos); + } + + return ypos - ystart; + } + + QPixmap PropertyRowWidget::createDragImage( + const QColor backgroundColor, const QColor borderColor, const float alpha, DragImageType imageType) + { + // Make the drag box as wide as the containing editor minus a gap each side for the border. + static constexpr int ParentEditorBorderSize = 2; + int width = GetContainingEditorFrameWidth() - ParentEditorBorderSize * 2; + int height = 0; + + if (imageType == DragImageType::IncludeVisibleChildren) + { + height = GetHeightOfRowAndVisibleChildren(); + } + else + { + height = rect().height(); + } + + const auto dpr = devicePixelRatioF(); + QPixmap dragImage(width * dpr, height * dpr); + dragImage.setDevicePixelRatio(dpr); + dragImage.fill(Qt::transparent); + + QRect imageRect = QRect(0, 0, width, height); + + QPainter dragPainter(&dragImage); + dragPainter.setCompositionMode(QPainter::CompositionMode_Source); + dragPainter.fillRect(imageRect, Qt::transparent); + dragPainter.setCompositionMode(QPainter::CompositionMode_SourceOver); + dragPainter.setOpacity(alpha); + dragPainter.fillRect(imageRect, backgroundColor); + + dragPainter.setOpacity(1.0f); + + int marginWidth = (imageRect.width() - rect().width()) / 2 + ParentEditorBorderSize - 1; + + if (imageType == DragImageType::IncludeVisibleChildren) + { + DrawDragImageAndVisibleChildrenInto(dragPainter, marginWidth, 0); + } + else + { + render(&dragPainter, QPoint(marginWidth, 0)); + } + + QPen pen; + pen.setColor(QColor(borderColor)); + pen.setWidth(1); + dragPainter.setPen(pen); + dragPainter.drawRect(0, 0, imageRect.width() - 1, imageRect.height() - 1); + + dragPainter.end(); + + return dragImage; + } } #include "UI/PropertyEditor/moc_PropertyRowWidget.cpp" diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.hxx index ebf7c67b21..68cc9b9cf9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.hxx @@ -45,6 +45,13 @@ namespace AzToolsFramework Q_PROPERTY(bool appendDefaultLabelToName READ GetAppendDefaultLabelToName WRITE AppendDefaultLabelToName) public: AZ_CLASS_ALLOCATOR(PropertyRowWidget, AZ::SystemAllocator, 0) + + enum class DragImageType + { + SingleRow, + IncludeVisibleChildren + }; + PropertyRowWidget(QWidget* pParent); virtual ~PropertyRowWidget(); @@ -86,6 +93,9 @@ namespace AzToolsFramework bool GetAppendDefaultLabelToName(); void AppendDefaultLabelToName(bool doAppend); + AZ::u32 GetChildRowCount() const; + PropertyRowWidget* GetChildRowByIndex(AZ::u32 index) const; + AZStd::vector& GetChildrenRows() { return m_childrenRows; } bool HasChildRows() const; @@ -124,6 +134,7 @@ namespace AzToolsFramework void SetSelectionEnabled(bool selectionEnabled); void SetSelected(bool selected); + bool GetSelected(); bool eventFilter(QObject *watched, QEvent *event) override; void paintEvent(QPaintEvent*) override; @@ -152,9 +163,18 @@ namespace AzToolsFramework bool CanChildrenBeReordered() const; bool CanBeReordered() const; + int GetIndexInParent() const; + bool CanMoveUp() const; + bool CanMoveDown() const; + + int GetContainingEditorFrameWidth(); + QPixmap createDragImage(const QColor backgroundColor, const QColor borderColor, const float alpha, DragImageType imageType); protected: int CalculateLabelWidth() const; + int GetHeightOfRowAndVisibleChildren(); + int DrawDragImageAndVisibleChildrenInto(QPainter& painter, int xpos, int ypos); + bool IsHidden(InstanceDataNode* node) const; struct ChangeNotification; @@ -216,6 +236,7 @@ namespace AzToolsFramework bool m_isMultiSizeContainer = false; bool m_isFixedSizeOrSmartPtrContainer = false; bool m_custom = false; + bool m_canChildrenBeReordered = false; bool m_isSelected = false; bool m_selectionEnabled = false; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.cpp index 36462bca66..5d5b00e83d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.cpp @@ -19,6 +19,7 @@ #include #include #include +#include AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option") // 'QTextFormat::d': class 'QSharedDataPointer' needs to have dll-interface to be used by clients of class 'QTextFormat' #include AZ_POP_DISABLE_WARNING @@ -1343,7 +1344,7 @@ namespace AzToolsFramework // calculate the index/offset of the instance data node in the container // (useful for notifying which element in a vector was modified/removed) - static size_t CalculateElementIndexInContainer( + static int CalculateElementIndexInContainer( InstanceDataNode* node, void* parentInstanceNode, AZ::SerializeContext::IDataContainer* container, AZStd::vector& nodeInstancesOut) { @@ -1358,7 +1359,7 @@ namespace AzToolsFramework } } - size_t elementIndex = 0; + int elementIndex = 0; void* elementPtr = nodeInstancesOut.empty() ? nullptr : nodeInstancesOut.front(); // find the index of the element we are about to remove @@ -1429,7 +1430,7 @@ namespace AzToolsFramework // if the element being modified exists in a container, calculate // the index to be passed through to PropertyNotify - const auto calculateElementIndex = [](InstanceDataNode* node) -> size_t { + const auto calculateElementIndex = [](InstanceDataNode* node) -> int { if (InstanceDataNode* parent = node->GetParent()) { if (AZ::SerializeContext::IDataContainer* container = parent->GetClassMetadata()->m_container) @@ -1656,6 +1657,221 @@ namespace AzToolsFramework AzToolsFramework::Refresh_EntireTree); } + InstanceDataNode* ReflectedPropertyEditor::FindContainerNodeForNode(InstanceDataNode* node) const + { + // Locate the owning container. There may be a level of indirection due to wrappers, such as DynamicSerializableField. + InstanceDataNode* pContainerNode = node->GetParent(); + if (!pContainerNode) + { + return nullptr; + } + + while (pContainerNode && !pContainerNode->GetClassMetadata()->m_container) + { + pContainerNode = pContainerNode->GetParent(); + node = node->GetParent(); + } + + // Check for pContainerNode again, can happen if a node is deleted during operation. + if (!pContainerNode) + { + return nullptr; + } + + if (IsParentAssociativeContainer(pContainerNode) && IsPairContainer(pContainerNode)) + { + // Go up one more level to the associative container, we'll remove the pair from that container + pContainerNode = pContainerNode->GetParent(); + node = node->GetParent(); + } + + AZ_Assert( + pContainerNode, "Failed to locate parent container for element \"%s\" of type %s.", + node->GetElementMetadata() ? node->GetElementMetadata()->m_name : node->GetClassMetadata()->m_name, + node->GetClassMetadata()->m_typeId.ToString().c_str()); + + return pContainerNode; + } + + InstanceDataNode* ReflectedPropertyEditor::GetNodeAtIndex(int index) + { + if (index >= m_impl->m_widgetsInDisplayOrder.size()) + { + return nullptr; + } + + return GetNodeFromWidget(m_impl->m_widgetsInDisplayOrder[index]); + } + + QSet ReflectedPropertyEditor::GetTopLevelWidgets() + { + return m_impl->getTopLevelWidgets(); + } + + void ReflectedPropertyEditor::ChangeNodeIndex(InstanceDataNode* containerNode, InstanceDataNode* node, int fromIndex, int toIndex) + { + auto container = containerNode->GetElementMetadata() + ? containerNode->GetElementMetadata()->m_genericClassInfo->GetClassData()->m_container + : nullptr; + + if (fromIndex == toIndex) + { + return; + } + + if (!container || container->GetAssociativeContainerInterface()) + { + return; + } + + AZ::Uuid typeId = node->GetClassMetadata()->m_typeId; + + if (m_impl->m_ptrNotify) + { + m_impl->m_ptrNotify->BeforePropertyModified(containerNode); + } + + const AZ::SerializeContext::ClassElement* containerClassElement = container->GetElement(container->GetDefaultElementNameCrc()); + + AZ::SerializeContext* serializeContext = nullptr; + AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext); + + // Backup the item we're moving. + void* srcElement = nullptr; + void* destElement = nullptr; + + int destIndex = -1; + int srcIndex = fromIndex; + + srcElement = container->GetElementByIndex(containerNode->GetInstance(0), containerClassElement, srcIndex); + + void* tmpBuffer = serializeContext->CloneObject(srcElement, typeId); + + // Shuffle all intervening items up (or down). + int indexOffset = (toIndex < fromIndex) ? -1 : 1; + + while (destIndex != toIndex - indexOffset) + { + destIndex = srcIndex; + srcIndex += indexOffset; + + destElement = srcElement; + + srcElement = container->GetElementByIndex(containerNode->GetInstance(0), containerClassElement, srcIndex); + + serializeContext->CloneObjectInplace(destElement, srcElement, typeId); + } + + // Now replace the final element with the one backed up previously. + destElement = srcElement; + + serializeContext->CloneObjectInplace(destElement, tmpBuffer, typeId); + + if (m_impl->m_ptrNotify) + { + m_impl->m_ptrNotify->AfterPropertyModified(containerNode); + m_impl->m_ptrNotify->SealUndoStack(); + } + + // Need to refresh any pinned inspectors as well to keep the container state in sync + QueueInvalidation(Refresh_Values); + AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast( + &AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_Values); + } + + void ReflectedPropertyEditor::MoveNodeToIndex(InstanceDataNode* node, int index) + { + InstanceDataNode* pContainerNode = FindContainerNodeForNode(node); + + if (!pContainerNode) + { + return; + } + + AZ::SerializeContext::IDataContainer* container = pContainerNode->GetClassMetadata()->m_container; + + AZStd::vector nodeInstancesOut; + const int elementIndex = CalculateElementIndexInContainer(node, pContainerNode->GetInstance(0), container, nodeInstancesOut); + + ChangeNodeIndex(pContainerNode, node, elementIndex, index); + } + + void ReflectedPropertyEditor::MoveNodeBefore(InstanceDataNode* nodeToMove, InstanceDataNode* nodeToMoveBefore) + { + InstanceDataNode* pContainerNode = FindContainerNodeForNode(nodeToMove); + InstanceDataNode* pContainerNodeTarget = FindContainerNodeForNode(nodeToMoveBefore); + + if (nodeToMove == nodeToMoveBefore) + { + return; + } + + // Can only move nodes within the same parent. + if (pContainerNode != pContainerNodeTarget) + { + return; + } + + AZ::SerializeContext::IDataContainer* container = pContainerNode->GetClassMetadata()->m_container; + + AZStd::vector nodeInstancesOut; + int elementIndex = CalculateElementIndexInContainer(nodeToMove, pContainerNode->GetInstance(0), container, nodeInstancesOut); + nodeInstancesOut.clear(); + int elementIndexTarget = + CalculateElementIndexInContainer(nodeToMoveBefore, pContainerNode->GetInstance(0), container, nodeInstancesOut); + + if (elementIndex < elementIndexTarget) + { + elementIndexTarget -= 1; + } + + ChangeNodeIndex(pContainerNode, nodeToMove, elementIndex, elementIndexTarget); + } + + void ReflectedPropertyEditor::MoveNodeAfter(InstanceDataNode* nodeToMove, InstanceDataNode* nodeToMoveBefore) + { + InstanceDataNode* pContainerNode = FindContainerNodeForNode(nodeToMove); + InstanceDataNode* pContainerNodeTarget = FindContainerNodeForNode(nodeToMoveBefore); + + if (nodeToMove == nodeToMoveBefore) + { + return; + } + + // Can only move nodes within the same parent. + if (pContainerNode != pContainerNodeTarget) + { + return; + } + + AZ::SerializeContext::IDataContainer* container = pContainerNode->GetClassMetadata()->m_container; + + AZStd::vector nodeInstancesOut; + int elementIndex = CalculateElementIndexInContainer(nodeToMove, pContainerNode->GetInstance(0), container, nodeInstancesOut); + nodeInstancesOut.clear(); + int elementIndexTarget = + CalculateElementIndexInContainer(nodeToMoveBefore, pContainerNode->GetInstance(0), container, nodeInstancesOut); + + if (elementIndex > elementIndexTarget) + { + elementIndexTarget += 1; + } + + ChangeNodeIndex(pContainerNode, nodeToMove, elementIndex, elementIndexTarget); + } + + int ReflectedPropertyEditor::GetNodeIndexInContainer(InstanceDataNode* node) + { + InstanceDataNode* pContainerNode = FindContainerNodeForNode(node); + + AZ::SerializeContext::IDataContainer* container = pContainerNode->GetClassMetadata()->m_container; + + AZStd::vector nodeInstancesOut; + int elementIndex = CalculateElementIndexInContainer(node, pContainerNode->GetInstance(0), container, nodeInstancesOut); + + return elementIndex; + } + void ReflectedPropertyEditor::OnPropertyRowRequestContainerRemoveItem(PropertyRowWidget* widget, InstanceDataNode* node) { // Locate the owning container. There may be a level of indirection due to wrappers, such as DynamicSerializableField. @@ -1690,7 +1906,7 @@ namespace AzToolsFramework // the index of the element being removed AZStd::vector nodeInstancesOut; - const size_t elementIndex = CalculateElementIndexInContainer( + const int elementIndex = CalculateElementIndexInContainer( node, pContainerNode->GetInstance(0), container, nodeInstancesOut); // pass the context as the last parameter to actually delete the related data. diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.hxx index b10e153162..28da540098 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.hxx @@ -155,9 +155,19 @@ namespace AzToolsFramework using VisibilityCallback = AZStd::function; void SetVisibilityCallback(VisibilityCallback callback); + void MoveNodeToIndex(InstanceDataNode* node, int index); + void MoveNodeBefore(InstanceDataNode* nodeToMove, InstanceDataNode* nodeToMoveBefore); + void MoveNodeAfter(InstanceDataNode* nodeToMove, InstanceDataNode* nodeToMoveBefore); + + int GetNodeIndexInContainer(InstanceDataNode* node); + InstanceDataNode* GetNodeAtIndex(int index); + QSet GetTopLevelWidgets(); signals: void OnExpansionContractionDone(); private: + InstanceDataNode* FindContainerNodeForNode(InstanceDataNode* node) const; + void ChangeNodeIndex(InstanceDataNode* containerNode, InstanceDataNode* node, int oldIndex, int newIndex); + class Impl; std::unique_ptr m_impl; From f7e536bfb1868203c53e20c2895718da45f4784e Mon Sep 17 00:00:00 2001 From: sphrose <82213493+sphrose@users.noreply.github.com> Date: Mon, 16 Aug 2021 12:37:12 +0100 Subject: [PATCH 59/70] compile fix - signed/unsigned mismatch (#3139) Signed-off-by: sphrose <82213493+sphrose@users.noreply.github.com> --- .../AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp index c3da1e69b0..604c6141d7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyRowWidget.cpp @@ -1755,7 +1755,7 @@ namespace AzToolsFramework return -1; } - for (int index = 0; index < GetParentRow()->GetChildRowCount(); index++) + for (AZ::u32 index = 0; index < GetParentRow()->GetChildRowCount(); index++) { if (GetParentRow()->GetChildrenRows()[index] == this) { From 5925bd22f6e0607f9fda0a705c6b3738c81bda24 Mon Sep 17 00:00:00 2001 From: jonawals Date: Mon, 16 Aug 2021 14:15:02 +0100 Subject: [PATCH 60/70] Further subdivide TIAF data by suite. (#3128) * Further subdivide TIAF data by suite. * Key fix typo. Signed-off-by: John --- .../TestImpactRuntimeConfigurationFactory.cpp | 25 ++++--------- .../TestImpactClientSequenceReport.h | 2 +- .../TestImpactConfiguration.h | 4 +-- .../Runtime/Code/Source/TestImpactRuntime.cpp | 5 +-- .../ConsoleFrontendConfig.in | 11 ++---- scripts/build/TestImpactAnalysis/tiaf.py | 3 +- .../tiaf_persistent_storage.py | 35 +++++++++++-------- .../tiaf_persistent_storage_local.py | 2 ++ .../tiaf_persistent_storage_s3.py | 6 ++-- 9 files changed, 42 insertions(+), 51 deletions(-) diff --git a/Code/Tools/TestImpactFramework/Frontend/Console/Code/Source/TestImpactRuntimeConfigurationFactory.cpp b/Code/Tools/TestImpactFramework/Frontend/Console/Code/Source/TestImpactRuntimeConfigurationFactory.cpp index 8ea32d6447..c2bc95a906 100644 --- a/Code/Tools/TestImpactFramework/Frontend/Console/Code/Source/TestImpactRuntimeConfigurationFactory.cpp +++ b/Code/Tools/TestImpactFramework/Frontend/Console/Code/Source/TestImpactRuntimeConfigurationFactory.cpp @@ -27,7 +27,7 @@ namespace TestImpact "relative_paths", "artifact_dir", "enumeration_cache_dir", - "test_impact_data_files", + "test_impact_data_file", "temp", "active", "target_sources", @@ -72,7 +72,7 @@ namespace TestImpact RelativePaths, ArtifactDir, EnumerationCacheDir, - TestImpactDataFiles, + TestImpactDataFile, TempWorkspace, ActiveWorkspace, TargetSources, @@ -138,31 +138,18 @@ namespace TestImpact tempWorkspaceConfig.m_artifactDirectory = GetAbsPathFromRelPath( tempWorkspaceConfig.m_root, tempWorkspace[Config::Keys[Config::RelativePaths]][Config::Keys[Config::ArtifactDir]].GetString()); + tempWorkspaceConfig.m_enumerationCacheDirectory = GetAbsPathFromRelPath( + tempWorkspaceConfig.m_root, + tempWorkspace[Config::Keys[Config::RelativePaths]][Config::Keys[Config::EnumerationCacheDir]].GetString()); return tempWorkspaceConfig; } - AZStd::array ParseTestImpactAnalysisDataFiles(const RepoPath& root, const rapidjson::Value& sparTiaFile) - { - AZStd::array sparTiaFiles; - sparTiaFiles[static_cast(SuiteType::Main)] = - GetAbsPathFromRelPath(root, sparTiaFile[SuiteTypeAsString(SuiteType::Main).c_str()].GetString()); - sparTiaFiles[static_cast(SuiteType::Periodic)] = - GetAbsPathFromRelPath(root, sparTiaFile[SuiteTypeAsString(SuiteType::Periodic).c_str()].GetString()); - sparTiaFiles[static_cast(SuiteType::Sandbox)] = - GetAbsPathFromRelPath(root, sparTiaFile[SuiteTypeAsString(SuiteType::Sandbox).c_str()].GetString()); - - return sparTiaFiles; - } - WorkspaceConfig::Active ParseActiveWorkspaceConfig(const rapidjson::Value& activeWorkspace) { WorkspaceConfig::Active activeWorkspaceConfig; const auto& relativePaths = activeWorkspace[Config::Keys[Config::RelativePaths]]; activeWorkspaceConfig.m_root = activeWorkspace[Config::Keys[Config::Root]].GetString(); - activeWorkspaceConfig.m_enumerationCacheDirectory - = GetAbsPathFromRelPath(activeWorkspaceConfig.m_root, relativePaths[Config::Keys[Config::EnumerationCacheDir]].GetString()); - activeWorkspaceConfig.m_sparTiaFiles = - ParseTestImpactAnalysisDataFiles(activeWorkspaceConfig.m_root, relativePaths[Config::Keys[Config::TestImpactDataFiles]]); + activeWorkspaceConfig.m_sparTiaFile = relativePaths[Config::Keys[Config::TestImpactDataFile]].GetString(); return activeWorkspaceConfig; } diff --git a/Code/Tools/TestImpactFramework/Runtime/Code/Include/TestImpactFramework/TestImpactClientSequenceReport.h b/Code/Tools/TestImpactFramework/Runtime/Code/Include/TestImpactFramework/TestImpactClientSequenceReport.h index e86123ddc7..1ddd1042e6 100644 --- a/Code/Tools/TestImpactFramework/Runtime/Code/Include/TestImpactFramework/TestImpactClientSequenceReport.h +++ b/Code/Tools/TestImpactFramework/Runtime/Code/Include/TestImpactFramework/TestImpactClientSequenceReport.h @@ -530,7 +530,7 @@ namespace TestImpact size_t GetTotalNumTimedOutTestRuns() const override; size_t GetTotalNumUnexecutedTestRuns() const override; - //! Returns the report for the discarded test runs. + // ImpactAnalysisSequenceReport overrides ... const TestRunSelection GetDiscardedTestRuns() const; //! Returns the report for the discarded test runs. diff --git a/Code/Tools/TestImpactFramework/Runtime/Code/Include/TestImpactFramework/TestImpactConfiguration.h b/Code/Tools/TestImpactFramework/Runtime/Code/Include/TestImpactFramework/TestImpactConfiguration.h index fcacd90e71..92dd454b01 100644 --- a/Code/Tools/TestImpactFramework/Runtime/Code/Include/TestImpactFramework/TestImpactConfiguration.h +++ b/Code/Tools/TestImpactFramework/Runtime/Code/Include/TestImpactFramework/TestImpactConfiguration.h @@ -37,14 +37,14 @@ namespace TestImpact { RepoPath m_root; //!< Path to the temporary workspace (cleaned prior to use). RepoPath m_artifactDirectory; //!< Path to read and write runtime artifacts to and from. + RepoPath m_enumerationCacheDirectory; //!< Path to the test enumerations cache. }; //! Active persistent data workspace configuration. struct Active { RepoPath m_root; //!< Path to the persistent workspace tracked by the repository. - RepoPath m_enumerationCacheDirectory; //!< Path to the test enumerations cache. - AZStd::array m_sparTiaFiles; //!< Paths to the test impact analysis data files for each test suite. + RepoPath m_sparTiaFile; //!< Paths to the test impact analysis data file. }; Temp m_temp; diff --git a/Code/Tools/TestImpactFramework/Runtime/Code/Source/TestImpactRuntime.cpp b/Code/Tools/TestImpactFramework/Runtime/Code/Source/TestImpactRuntime.cpp index 8a9d96bca8..515118dd7a 100644 --- a/Code/Tools/TestImpactFramework/Runtime/Code/Source/TestImpactRuntime.cpp +++ b/Code/Tools/TestImpactFramework/Runtime/Code/Source/TestImpactRuntime.cpp @@ -275,7 +275,7 @@ namespace TestImpact m_testEngine = AZStd::make_unique( m_config.m_repo.m_root, m_config.m_target.m_outputDirectory, - m_config.m_workspace.m_active.m_enumerationCacheDirectory, + m_config.m_workspace.m_temp.m_enumerationCacheDirectory, m_config.m_workspace.m_temp.m_artifactDirectory, m_config.m_testEngine.m_testRunner.m_binary, m_config.m_testEngine.m_instrumentation.m_binary, @@ -289,7 +289,8 @@ namespace TestImpact } else { - m_sparTiaFile = m_config.m_workspace.m_active.m_sparTiaFiles[static_cast(m_suiteFilter)].String(); + m_sparTiaFile = + m_config.m_workspace.m_active.m_root / RepoPath(SuiteTypeAsString(m_suiteFilter)) / m_config.m_workspace.m_active.m_sparTiaFile; } // Populate the dynamic dependency map with the existing source coverage data (if any) diff --git a/cmake/TestImpactFramework/ConsoleFrontendConfig.in b/cmake/TestImpactFramework/ConsoleFrontendConfig.in index 17fbd217d7..3b6318e1e0 100644 --- a/cmake/TestImpactFramework/ConsoleFrontendConfig.in +++ b/cmake/TestImpactFramework/ConsoleFrontendConfig.in @@ -15,19 +15,14 @@ "temp": { "root": "${temp_dir}", "relative_paths": { - "artifact_dir": "RuntimeArtifact" + "artifact_dir": "RuntimeArtifact", + "enumeration_cache_dir": "EnumerationCache" } }, "active": { "root": "${active_dir}", "relative_paths": { - "test_impact_data_files": { - "main": "TestImpactData.main.spartia", - "periodic": "TestImpactData.periodic.spartia", - "sandbox": "TestImpactData.sandbox.spartia" - }, - "enumeration_cache_dir": "EnumerationCache", - "last_build_target_list_file": "LastRunBuildTargets.json" + "test_impact_data_file": "TestImpactData.spartia" } }, "historic": { diff --git a/scripts/build/TestImpactAnalysis/tiaf.py b/scripts/build/TestImpactAnalysis/tiaf.py index e8faef30e3..27fbaf451f 100644 --- a/scripts/build/TestImpactAnalysis/tiaf.py +++ b/scripts/build/TestImpactAnalysis/tiaf.py @@ -230,7 +230,7 @@ class TestImpact: # Flag for corner case where: # 1. TIAF was already run previously for this commit. - # 2. There was no last commit hash when TIAF last ran on this commit (due to no coverage data existing get for this branch) + # 2. There was no last commit hash when TIAF last ran on this commit (due to no coverage data existing yet for this branch) # 3. TIAF has not been run on any other commits between the run for this commit and the last run for this commit. # The above results in TIAF being stuck in a state of generating an empty change list (and thus doing no work until another # commit comes in) which is problematic if the commit needs to be re-run for whatever reason so in these conditions we revert @@ -323,7 +323,6 @@ class TestImpact: logger.info(f"Args: {unpacked_args}") runtime_result = subprocess.run([str(self._tiaf_bin)] + args) report = None - # If the sequence completed (with or without failures) we will update the historical meta-data if runtime_result.returncode == 0 or runtime_result.returncode == 7: logger.info("Test impact analysis runtime returned successfully.") diff --git a/scripts/build/TestImpactAnalysis/tiaf_persistent_storage.py b/scripts/build/TestImpactAnalysis/tiaf_persistent_storage.py index 3fff05b549..5445c1f955 100644 --- a/scripts/build/TestImpactAnalysis/tiaf_persistent_storage.py +++ b/scripts/build/TestImpactAnalysis/tiaf_persistent_storage.py @@ -17,11 +17,11 @@ logger = get_logger(__file__) class PersistentStorage(ABC): WORKSPACE_KEY = "workspace" - LAST_RUNS_KEY = "last_runs" + HISTORIC_SEQUENCES_KEY = "historic_sequences" ACTIVE_KEY = "active" ROOT_KEY = "root" RELATIVE_PATHS_KEY = "relative_paths" - TEST_IMPACT_DATA_FILES_KEY = "test_impact_data_files" + TEST_IMPACT_DATA_FILE_KEY = "test_impact_data_file" LAST_COMMIT_HASH_KEY = "last_commit_hash" COVERAGE_DATA_KEY = "coverage_data" @@ -35,19 +35,21 @@ class PersistentStorage(ABC): """ # Work on the assumption that there is no historic meta-data (a valid state to be in, should none exist) + self._suite = suite self._last_commit_hash = None self._has_historic_data = False self._has_previous_last_commit_hash = False self._this_commit_hash = commit self._this_commit_hash_last_commit_hash = None self._historic_data = None - logger.info(f"Attempting to access persistent storage for the commit {self._this_commit_hash}") + logger.info(f"Attempting to access persistent storage for the commit '{self._this_commit_hash}' for suite '{self._suite}'") try: # The runtime expects the coverage data to be in the location specified in the config file (unless overridden with # the --datafile command line argument, which the TIAF scripts do not do) self._active_workspace = pathlib.Path(config[self.WORKSPACE_KEY][self.ACTIVE_KEY][self.ROOT_KEY]) - unpacked_coverage_data_file = config[self.WORKSPACE_KEY][self.ACTIVE_KEY][self.RELATIVE_PATHS_KEY][self.TEST_IMPACT_DATA_FILES_KEY][suite] + self._active_workspace = self._active_workspace.joinpath(pathlib.Path(self._suite)) + unpacked_coverage_data_file = config[self.WORKSPACE_KEY][self.ACTIVE_KEY][self.RELATIVE_PATHS_KEY][self.TEST_IMPACT_DATA_FILE_KEY] except KeyError as e: raise SystemError(f"The config does not contain the key {str(e)}.") @@ -70,25 +72,27 @@ class PersistentStorage(ABC): self._last_commit_hash = self._historic_data[self.LAST_COMMIT_HASH_KEY] logger.info(f"Last commit hash '{self._last_commit_hash}' found.") - if self.LAST_RUNS_KEY in self._historic_data: - # Last commit hash for the sequence that was run for this commit previously (if any) - if self._this_commit_hash in self._historic_data[self.LAST_RUNS_KEY]: + # Last commit hash for the sequence that was run for this commit previously (if any) + if self.HISTORIC_SEQUENCES_KEY in self._historic_data: + if self._this_commit_hash in self._historic_data[self.HISTORIC_SEQUENCES_KEY]: # 'None' is a valid value for the previously used last commit hash if there was no coverage data at that time - self._this_commit_hash_last_commit_hash = self._historic_data[self.LAST_RUNS_KEY][self._this_commit_hash] + self._this_commit_hash_last_commit_hash = self._historic_data[self.HISTORIC_SEQUENCES_KEY][self._this_commit_hash] self._has_previous_last_commit_hash = self._this_commit_hash_last_commit_hash is not None if self._has_previous_last_commit_hash: logger.info(f"Last commit hash '{self._this_commit_hash_last_commit_hash}' was used previously for this commit.") else: - logger.info(f"Prior sequence data found for this commit but it is empty (there was no coverage data vailable at that time).") + logger.info(f"Prior sequence data found for this commit but it is empty (there was no coverage data available at that time).") else: logger.info(f"No prior sequence data found for commit '{self._this_commit_hash}', this is the first sequence for this commit.") else: logger.info(f"No prior sequence data found for any commits.") - # Create the active workspace directory where the coverage data file will be placed and unpack the coverage data so - # it is accessible by the runtime + # Create the active workspace directory for the unpacked historic data files so they are accessible by the runtime self._active_workspace.mkdir(exist_ok=True) + + # Coverage file + logger.info(f"Writing coverage data to '{self._unpacked_coverage_data_file}'.") with open(self._unpacked_coverage_data_file, "w", newline='\n') as coverage_data: coverage_data.write(self._historic_data[self.COVERAGE_DATA_KEY]) @@ -117,9 +121,12 @@ class PersistentStorage(ABC): self._historic_data[self.LAST_COMMIT_HASH_KEY] = self._this_commit_hash # Last commit hash for this commit - if not self.LAST_RUNS_KEY in self._historic_data: - self._historic_data[self.LAST_RUNS_KEY] = {} - self._historic_data[self.LAST_RUNS_KEY][self._this_commit_hash] = self._last_commit_hash + if not self.HISTORIC_SEQUENCES_KEY in self._historic_data: + self._historic_data[self.HISTORIC_SEQUENCES_KEY] = {} + self._historic_data[self.HISTORIC_SEQUENCES_KEY][self._this_commit_hash] = self._last_commit_hash + + # Test runs for this completed sequence + self._historic_data[self.PREVIOUS_TEST_RUNS_KEY] = test_runs # Coverage data for this branch with open(self._unpacked_coverage_data_file, "r") as coverage_data: diff --git a/scripts/build/TestImpactAnalysis/tiaf_persistent_storage_local.py b/scripts/build/TestImpactAnalysis/tiaf_persistent_storage_local.py index c72fafc580..7ad9155a41 100644 --- a/scripts/build/TestImpactAnalysis/tiaf_persistent_storage_local.py +++ b/scripts/build/TestImpactAnalysis/tiaf_persistent_storage_local.py @@ -32,10 +32,12 @@ class PersistentStorageLocal(PersistentStorage): try: # Attempt to obtain the local persistent data location specified in the runtime config file self._historic_workspace = pathlib.Path(config[self.WORKSPACE_KEY][self.HISTORIC_KEY][self.ROOT_KEY]) + self._historic_workspace = self._historic_workspace.joinpath(pathlib.Path(self._suite)) historic_data_file = pathlib.Path(config[self.WORKSPACE_KEY][self.HISTORIC_KEY][self.RELATIVE_PATHS_KEY][self.DATA_KEY]) # Attempt to unpack the local historic data file self._historic_data_file = self._historic_workspace.joinpath(historic_data_file) + logger.info(f"Attempting to retrieve historic data at location '{self._historic_data_file}'...") if self._historic_data_file.is_file(): with open(self._historic_data_file, "r") as historic_data_raw: historic_data_json = historic_data_raw.read() diff --git a/scripts/build/TestImpactAnalysis/tiaf_persistent_storage_s3.py b/scripts/build/TestImpactAnalysis/tiaf_persistent_storage_s3.py index 074caf73a1..175eb3148d 100644 --- a/scripts/build/TestImpactAnalysis/tiaf_persistent_storage_s3.py +++ b/scripts/build/TestImpactAnalysis/tiaf_persistent_storage_s3.py @@ -43,9 +43,9 @@ class PersistentStorageS3(PersistentStorage): # historic_data.json.zip is the file containing the coverage and meta-data of the last TIAF sequence run historic_data_file = f"historic_data.{object_extension}" - # The location of the data is in the form // so the build config of each branch gets its own historic data - self._historic_data_dir = f'{root_dir}/{branch}/{config[self.META_KEY][self.BUILD_CONFIG_KEY]}' - self._historic_data_key = f'{self._historic_data_dir}/{historic_data_file}' + # The location of the data is in the form /// so the build config of each branch gets its own historic data + self._historic_data_dir = f"{root_dir}/{branch}/{config[self.META_KEY][self.BUILD_CONFIG_KEY]}/{self._suite}" + self._historic_data_key = f"{self._historic_data_dir}/{historic_data_file}" logger.info(f"Attempting to retrieve historic data for branch '{branch}' at location '{self._historic_data_key}' on bucket '{s3_bucket}'...") self._s3 = boto3.resource("s3") From e630e3324dc5836fcfea328d9e002fa0877f060b Mon Sep 17 00:00:00 2001 From: amzn-sean <75276488+amzn-sean@users.noreply.github.com> Date: Mon, 16 Aug 2021 15:46:46 +0100 Subject: [PATCH 61/70] fixed joint crash when no lead entity is selected (#2867) Signed-off-by: amzn-sean <75276488+amzn-sean@users.noreply.github.com> --- Gems/PhysX/Code/Source/BallJointComponent.cpp | 19 +++++- .../PhysX/Code/Source/FixedJointComponent.cpp | 18 ++++- .../PhysX/Code/Source/HingeJointComponent.cpp | 18 ++++- .../Code/Source/Joint/PhysXJointUtils.cpp | 15 +++-- Gems/PhysX/Code/Tests/PhysXJointsTest.cpp | 66 +++++++++++++++++-- 5 files changed, 121 insertions(+), 15 deletions(-) diff --git a/Gems/PhysX/Code/Source/BallJointComponent.cpp b/Gems/PhysX/Code/Source/BallJointComponent.cpp index 12323e5077..60f7888b0d 100644 --- a/Gems/PhysX/Code/Source/BallJointComponent.cpp +++ b/Gems/PhysX/Code/Source/BallJointComponent.cpp @@ -46,11 +46,26 @@ namespace PhysX JointComponent::LeadFollowerInfo leadFollowerInfo; ObtainLeadFollowerInfo(leadFollowerInfo); - if (!leadFollowerInfo.m_followerActor) + if (leadFollowerInfo.m_followerActor == nullptr || + leadFollowerInfo.m_followerBody == nullptr) { return; } + // if there is no lead body, this will be a constraint of the follower's global position, so use invalid body handle. + AzPhysics::SimulatedBodyHandle parentHandle = AzPhysics::InvalidSimulatedBodyHandle; + if (leadFollowerInfo.m_leadBody != nullptr) + { + parentHandle = leadFollowerInfo.m_leadBody->m_bodyHandle; + } + else + { + AZ_TracePrintf( + "PhysX", "Entity [%s] Ball Joint component missing lead entity. This joint will be a global constraint on the follower's global position.", + GetEntity()->GetName().c_str()); + } + + BallJointConfiguration configuration; configuration.m_parentLocalPosition = leadFollowerInfo.m_leadLocal.GetTranslation(); configuration.m_parentLocalRotation = leadFollowerInfo.m_leadLocal.GetRotation(); @@ -65,7 +80,7 @@ namespace PhysX m_jointHandle = sceneInterface->AddJoint( leadFollowerInfo.m_followerBody->m_sceneOwner, &configuration, - leadFollowerInfo.m_leadBody->m_bodyHandle, + parentHandle, leadFollowerInfo.m_followerBody->m_bodyHandle); m_jointSceneOwner = leadFollowerInfo.m_followerBody->m_sceneOwner; } diff --git a/Gems/PhysX/Code/Source/FixedJointComponent.cpp b/Gems/PhysX/Code/Source/FixedJointComponent.cpp index 53a9946998..82c8cc485c 100644 --- a/Gems/PhysX/Code/Source/FixedJointComponent.cpp +++ b/Gems/PhysX/Code/Source/FixedJointComponent.cpp @@ -54,11 +54,25 @@ namespace PhysX JointComponent::LeadFollowerInfo leadFollowerInfo; ObtainLeadFollowerInfo(leadFollowerInfo); - if (!leadFollowerInfo.m_followerActor) + if (leadFollowerInfo.m_followerActor == nullptr || + leadFollowerInfo.m_followerBody == nullptr) { return; } + // if there is no lead body, this will be a constraint of the follower's global position, so use invalid body handle. + AzPhysics::SimulatedBodyHandle parentHandle = AzPhysics::InvalidSimulatedBodyHandle; + if (leadFollowerInfo.m_leadBody != nullptr) + { + parentHandle = leadFollowerInfo.m_leadBody->m_bodyHandle; + } + else + { + AZ_TracePrintf("PhysX", + "Entity [%s] Fixed Joint component missing lead entity. This joint will be a global constraint on the follower's global position.", + GetEntity()->GetName().c_str()); + } + FixedJointConfiguration configuration; configuration.m_parentLocalPosition = leadFollowerInfo.m_leadLocal.GetTranslation(); configuration.m_parentLocalRotation = leadFollowerInfo.m_leadLocal.GetRotation(); @@ -72,7 +86,7 @@ namespace PhysX m_jointHandle = sceneInterface->AddJoint( leadFollowerInfo.m_followerBody->m_sceneOwner, &configuration, - leadFollowerInfo.m_leadBody->m_bodyHandle, + parentHandle, leadFollowerInfo.m_followerBody->m_bodyHandle); m_jointSceneOwner = leadFollowerInfo.m_followerBody->m_sceneOwner; } diff --git a/Gems/PhysX/Code/Source/HingeJointComponent.cpp b/Gems/PhysX/Code/Source/HingeJointComponent.cpp index f275d32dc7..5edf1803c4 100644 --- a/Gems/PhysX/Code/Source/HingeJointComponent.cpp +++ b/Gems/PhysX/Code/Source/HingeJointComponent.cpp @@ -48,12 +48,24 @@ namespace PhysX JointComponent::LeadFollowerInfo leadFollowerInfo; ObtainLeadFollowerInfo(leadFollowerInfo); if (leadFollowerInfo.m_followerActor == nullptr || - leadFollowerInfo.m_leadBody == nullptr || leadFollowerInfo.m_followerBody == nullptr) { return; } + // if there is no lead body, this will be a constraint of the follower's global position, so use invalid body handle. + AzPhysics::SimulatedBodyHandle parentHandle = AzPhysics::InvalidSimulatedBodyHandle; + if (leadFollowerInfo.m_leadBody != nullptr) + { + parentHandle = leadFollowerInfo.m_leadBody->m_bodyHandle; + } + else + { + AZ_TracePrintf( + "PhysX", "Entity [%s] Hinge Joint component missing lead entity. This joint will be a global constraint on the follower's global position.", + GetEntity()->GetName().c_str()); + } + HingeJointConfiguration configuration; configuration.m_parentLocalPosition = leadFollowerInfo.m_leadLocal.GetTranslation(); configuration.m_parentLocalRotation = leadFollowerInfo.m_leadLocal.GetRotation(); @@ -66,7 +78,9 @@ namespace PhysX if (auto* sceneInterface = AZ::Interface::Get()) { m_jointHandle = sceneInterface->AddJoint( - leadFollowerInfo.m_followerBody->m_sceneOwner, &configuration, leadFollowerInfo.m_leadBody->m_bodyHandle, + leadFollowerInfo.m_followerBody->m_sceneOwner, + &configuration, + parentHandle, leadFollowerInfo.m_followerBody->m_bodyHandle); m_jointSceneOwner = leadFollowerInfo.m_followerBody->m_sceneOwner; } diff --git a/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.cpp b/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.cpp index 5b63a43966..3558c9fb56 100644 --- a/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.cpp +++ b/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.cpp @@ -190,8 +190,9 @@ namespace PhysX { { PxJointActorData actorData = GetJointPxActors(sceneHandle, parentBodyHandle, childBodyHandle); - if (!actorData.parentActor || !actorData.childActor) + if (actorData.parentActor == nullptr && actorData.childActor == nullptr) { + AZ_Warning("PhysX Joint", false, "CreateJoint failed - at least one body must be a PxRigidActor."); return nullptr; } @@ -239,7 +240,8 @@ namespace PhysX { { PxJointActorData actorData = GetJointPxActors(sceneHandle, parentBodyHandle, childBodyHandle); - if (!actorData.parentActor || !actorData.childActor) + //only check the child actor, as a null parent actor means this joint is a global constraint. + if (!actorData.childActor) { return nullptr; } @@ -252,7 +254,8 @@ namespace PhysX { { PHYSX_SCENE_READ_LOCK(actorData.childActor->getScene()); - joint = physx::PxFixedJointCreate(PxGetPhysics(), + joint = physx::PxFixedJointCreate( + PxGetPhysics(), actorData.parentActor, PxMathConvert(parentLocalTM), actorData.childActor, PxMathConvert(childLocalTM)); } @@ -272,7 +275,8 @@ namespace PhysX { { PxJointActorData actorData = GetJointPxActors(sceneHandle, parentBodyHandle, childBodyHandle); - if (!actorData.parentActor || !actorData.childActor) + // only check the child actor, as a null parent actor means this joint is a global constraint. + if (!actorData.childActor) { return nullptr; } @@ -306,7 +310,8 @@ namespace PhysX { { PxJointActorData actorData = GetJointPxActors(sceneHandle, parentBodyHandle, childBodyHandle); - if (!actorData.parentActor || !actorData.childActor) + // only check the child actor, as a null parent actor means this joint is a global constraint. + if (!actorData.childActor) { return nullptr; } diff --git a/Gems/PhysX/Code/Tests/PhysXJointsTest.cpp b/Gems/PhysX/Code/Tests/PhysXJointsTest.cpp index ff9cf11cca..ac5a99e29a 100644 --- a/Gems/PhysX/Code/Tests/PhysXJointsTest.cpp +++ b/Gems/PhysX/Code/Tests/PhysXJointsTest.cpp @@ -123,7 +123,7 @@ namespace PhysX const AZ::Vector3 followerEndPosition = RunJointTest(m_defaultScene, followerEntity->GetId()); - EXPECT_TRUE(followerEndPosition.GetX() > followerPosition.GetX()); + EXPECT_GT(followerEndPosition.GetX(), followerPosition.GetX()); } TEST_F(PhysXJointsTest, Joint_HingeJoint_FollowerSwingsAroundLead) @@ -164,8 +164,8 @@ namespace PhysX const AZ::Vector3 followerEndPosition = RunJointTest(m_defaultScene, followerEntity->GetId()); - EXPECT_TRUE(followerEndPosition.GetX() > followerPosition.GetX()); - EXPECT_TRUE(abs(followerEndPosition.GetZ()) > FLT_EPSILON); + EXPECT_GT(followerEndPosition.GetX(), followerPosition.GetX()); + EXPECT_GT(abs(followerEndPosition.GetZ()), FLT_EPSILON); } TEST_F(PhysXJointsTest, Joint_BallJoint_FollowerSwingsUpAboutLead) @@ -206,7 +206,65 @@ namespace PhysX const AZ::Vector3 followerEndPosition = RunJointTest(m_defaultScene, followerEntity->GetId()); - EXPECT_TRUE(followerEndPosition.GetZ() > followerPosition.GetZ()); + EXPECT_GT(followerEndPosition.GetZ(), followerPosition.GetZ()); + } + + TEST_F(PhysXJointsTest, Joint_BallJoint_GlobalConstraint) + { + // Place an entity in the world with a rigid body, physx collider, and a ball joint components. + // Do not set a lead entity on the ball joint component. + // Set entity's initial velocity to 10 in the X and Y directions on the rigid body component. + // The entity should swing up on the global constraint. + + const AZ::Vector3 followerPosition(0.0f, 0.0f, -1.0f); + const AZ::Vector3 followerInitialLinearVelocity(10.0f, 10.0f, 0.0f); + + const AZ::Vector3 jointLocalPosition(0.0f, 0.0f, 2.0f); + const AZ::Quaternion jointLocalRotation = AZ::Quaternion::CreateRotationY(90.0f); + const AZ::Transform jointLocalTransform = AZ::Transform::CreateFromQuaternionAndTranslation(jointLocalRotation, jointLocalPosition); + + //we want a global constraint, so leave the lead entity unset. + auto jointConfig = AZStd::make_shared(); + jointConfig->m_localTransformFromFollower = jointLocalTransform; + + auto jointLimits = AZStd::make_shared(); + jointLimits->m_isLimited = false; + + auto followerEntity = AddBodyColliderEntity( + m_testSceneHandle, followerPosition, followerInitialLinearVelocity, jointConfig, nullptr, jointLimits); + + const AZ::Vector3 followerEndPosition = RunJointTest(m_defaultScene, followerEntity->GetId()); + + EXPECT_GT(followerEndPosition.GetZ(), followerPosition.GetZ()); + } + + TEST_F(PhysXJointsTest, Joint_HingeJoint_GlobalConstraint) + { + // Place an entity in the world with a rigid body, physx collider, and a hinge joint components. + // Do not set a lead entity on the hinge joint component. + // Set entity's initial velocity to 10 in the X and Y directions on the rigid body component. + // The entity should swing up on the global constraint. + + const AZ::Vector3 followerPosition(0.0f, 0.0f, -1.0f); + const AZ::Vector3 followerInitialLinearVelocity(10.0f, 10.0f, 0.0f); + + const AZ::Vector3 jointLocalPosition(0.0f, 0.0f, 2.0f); + const AZ::Quaternion jointLocalRotation = AZ::Quaternion::CreateFromEulerAnglesDegrees(AZ::Vector3(0.0f, 180.0f, 90.0f)); + const AZ::Transform jointLocalTransform = AZ::Transform::CreateFromQuaternionAndTranslation(jointLocalRotation, jointLocalPosition); + + // do not set the lead entity as that makes this a global constraint + auto jointConfig = AZStd::make_shared(); + jointConfig->m_localTransformFromFollower = jointLocalTransform; + + auto jointLimits = AZStd::make_shared(); + jointLimits->m_isLimited = false; + + auto followerEntity = AddBodyColliderEntity( + m_testSceneHandle, followerPosition, followerInitialLinearVelocity, jointConfig, nullptr, jointLimits); + + const AZ::Vector3 followerEndPosition = RunJointTest(m_defaultScene, followerEntity->GetId()); + + EXPECT_GT(followerEndPosition.GetZ(), followerPosition.GetZ()); } // for some reason TYPED_TEST_CASE with the fixture is not working on Android + Linux From 252c268ffdf340ce43411f1b93c05a39eb92b35b Mon Sep 17 00:00:00 2001 From: jonawals Date: Mon, 16 Aug 2021 16:09:36 +0100 Subject: [PATCH 62/70] Fix corrupt merge. (#3142) * Further subdivide TIAF data by suite. * Key fix typo. Signed-off-by: John --- scripts/build/TestImpactAnalysis/tiaf_persistent_storage.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/scripts/build/TestImpactAnalysis/tiaf_persistent_storage.py b/scripts/build/TestImpactAnalysis/tiaf_persistent_storage.py index 5445c1f955..e499b0303c 100644 --- a/scripts/build/TestImpactAnalysis/tiaf_persistent_storage.py +++ b/scripts/build/TestImpactAnalysis/tiaf_persistent_storage.py @@ -125,9 +125,6 @@ class PersistentStorage(ABC): self._historic_data[self.HISTORIC_SEQUENCES_KEY] = {} self._historic_data[self.HISTORIC_SEQUENCES_KEY][self._this_commit_hash] = self._last_commit_hash - # Test runs for this completed sequence - self._historic_data[self.PREVIOUS_TEST_RUNS_KEY] = test_runs - # Coverage data for this branch with open(self._unpacked_coverage_data_file, "r") as coverage_data: self._historic_data[self.COVERAGE_DATA_KEY] = coverage_data.read() From 4f2d4d00ec612a5a7a9ad946ebedf6d04841640c Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Mon, 16 Aug 2021 08:40:27 -0700 Subject: [PATCH 63/70] Auto-completing the inserted text by pressing TAB within Editor's Console results in a silent crash Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Legacy/CrySystem/XConsole.cpp | 57 ++++++++---------------------- 1 file changed, 14 insertions(+), 43 deletions(-) diff --git a/Code/Legacy/CrySystem/XConsole.cpp b/Code/Legacy/CrySystem/XConsole.cpp index ae07f86312..36443fb9ee 100644 --- a/Code/Legacy/CrySystem/XConsole.cpp +++ b/Code/Legacy/CrySystem/XConsole.cpp @@ -2873,7 +2873,7 @@ void CXConsole::Paste() ////////////////////////////////////////////////////////////////////////// int CXConsole::GetNumVars() { - return (int)m_mapVariables.size(); + return static_cast(m_mapVariables.size()); } ////////////////////////////////////////////////////////////////////////// @@ -3132,7 +3132,6 @@ char* CXConsole::GetCheatVarAt(uint32 nOffset) ////////////////////////////////////////////////////////////////////////// size_t CXConsole::GetSortedVars(AZStd::vector& pszArray, const char* szPrefix) { - size_t i = 0; size_t iPrefixLen = szPrefix ? strlen(szPrefix) : 0; // variables @@ -3140,11 +3139,6 @@ size_t CXConsole::GetSortedVars(AZStd::vector& pszArray, con ConsoleVariablesMap::const_iterator it, end = m_mapVariables.end(); for (it = m_mapVariables.begin(); it != end; ++it) { - if (i >= pszArray.size()) - { - break; - } - if (szPrefix) { if (_strnicmp(it->first, szPrefix, iPrefixLen) != 0) @@ -3158,9 +3152,7 @@ size_t CXConsole::GetSortedVars(AZStd::vector& pszArray, con continue; } - pszArray[i] = it->first; - - i++; + pszArray.push_back(it->first); } } @@ -3169,11 +3161,6 @@ size_t CXConsole::GetSortedVars(AZStd::vector& pszArray, con ConsoleCommandsMap::iterator it, end = m_mapCommands.end(); for (it = m_mapCommands.begin(); it != end; ++it) { - if (i >= pszArray.size()) - { - break; - } - if (szPrefix) { if (_strnicmp(it->first.c_str(), szPrefix, iPrefixLen) != 0) @@ -3187,25 +3174,18 @@ size_t CXConsole::GetSortedVars(AZStd::vector& pszArray, con continue; } - pszArray[i] = it->first.c_str(); - - i++; + pszArray.push_back(it->first.c_str()); } } - if (i != 0) - { - std::sort(pszArray.begin(), pszArray.end()); - } - - return i; + std::sort(pszArray.begin(), pszArray.end()); + return pszArray.size(); } ////////////////////////////////////////////////////////////////////////// void CXConsole::FindVar(const char* substr) { AZStd::vector cmds; - cmds.resize(GetNumVars() + m_mapCommands.size()); size_t cmdCount = GetSortedVars(cmds); for (size_t i = 0; i < cmdCount; i++) @@ -3231,10 +3211,9 @@ const char* CXConsole::AutoComplete(const char* substr) // following code can be optimized AZStd::vector cmds; - cmds.resize(GetNumVars() + m_mapCommands.size()); size_t cmdCount = GetSortedVars(cmds); - size_t substrLen = strlen(substr); + size_t substrLen = substr ? strlen(substr) : 0; // If substring is empty return first command. if (substrLen == 0 && cmdCount > 0) @@ -3246,7 +3225,7 @@ const char* CXConsole::AutoComplete(const char* substr) for (size_t i = 0; i < cmdCount; i++) { const char* szCmd = cmds[i].data(); - size_t cmdlen = strlen(szCmd); + size_t cmdlen = cmds[i].size(); if (cmdlen >= substrLen && memcmp(szCmd, substr, substrLen) == 0) { if (substrLen == cmdlen) @@ -3267,7 +3246,7 @@ const char* CXConsole::AutoComplete(const char* substr) { const char* szCmd = cmds[i].data(); - size_t cmdlen = strlen(szCmd); + size_t cmdlen = cmds[i].size(); if (cmdlen >= substrLen && azstrnicmp(szCmd, substr, substrLen) == 0) { if (substrLen == cmdlen) @@ -3301,27 +3280,19 @@ void CXConsole::SetInputLine(const char* szLine) const char* CXConsole::AutoCompletePrev(const char* substr) { AZStd::vector cmds; - cmds.resize(GetNumVars() + m_mapCommands.size()); - size_t cmdCount = GetSortedVars(cmds); + GetSortedVars(cmds); // If substring is empty return last command. - if (strlen(substr) == 0 && cmds.size() > 0) + if (strlen(substr) == 0 && !cmds.empty()) { - return cmds[cmdCount - 1].data(); + return cmds.back().data(); } - for (unsigned int i = 0; i < cmdCount; i++) + for (const AZStd::string_view& cmd : cmds) { - if (azstricmp(substr, cmds[i].data()) == 0) + if (azstricmp(substr, cmd.data()) == 0) { - if (i > 0) - { - return cmds[i - 1].data(); - } - else - { - return cmds[0].data(); - } + return cmd.data(); } } return AutoComplete(substr); From 994403bfa018dd96e8494c5b57fa8ba08b849819 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Mon, 16 Aug 2021 11:56:50 -0500 Subject: [PATCH 64/70] Updated Radius Weight Modifier component name for consistency. Signed-off-by: Chris Galvan --- .../EditorRadiusWeightModifierComponent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/RadiusWeightModifier/EditorRadiusWeightModifierComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/RadiusWeightModifier/EditorRadiusWeightModifierComponent.cpp index 039255276c..219ab6acb9 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/RadiusWeightModifier/EditorRadiusWeightModifierComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/RadiusWeightModifier/EditorRadiusWeightModifierComponent.cpp @@ -25,7 +25,7 @@ namespace AZ if (AZ::EditContext* editContext = serializeContext->GetEditContext()) { editContext->Class( - "Radius Weight Modifier", "Modifies PostFX override factor based on proximity of an influencer against this entity's bounding sphere") + "PostFX Radius Weight Modifier", "Modifies PostFX override factor based on proximity of an influencer against this entity's bounding sphere") ->ClassElement(Edit::ClassElements::EditorData, "") ->Attribute(Edit::Attributes::Category, "Atom") ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/Component_Placeholder.svg") From e2b4d8e50249727294bfdd0856b0d935f311aaa2 Mon Sep 17 00:00:00 2001 From: Jacob Hilliard <64656371+jcbhl@users.noreply.github.com> Date: Mon, 16 Aug 2021 10:13:24 -0700 Subject: [PATCH 65/70] Profiler: Runtime region name support (#2924) * Profiler: add support for runtime region names * Profiler: fix group name collisions * Profiler: use set of GroupRegionNames * Profiler: add comments + named constant Signed-off-by: Jacob Hilliard --- .../RHI/Code/Include/Atom/RHI/CpuProfiler.h | 16 +++++++++++ .../Code/Include/Atom/RHI/CpuProfilerImpl.h | 12 +++++++++ .../RHI/Code/Source/RHI/CpuProfilerImpl.cpp | 27 +++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfiler.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfiler.h index 2248474820..3fedc99566 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfiler.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfiler.h @@ -30,6 +30,12 @@ namespace AZ const char* const m_groupName = nullptr; const char* const m_regionName = nullptr; + + struct Hash + { + AZStd::size_t operator()(const GroupRegionName& name) const; + }; + bool operator==(const GroupRegionName& other) const; }; CachedTimeRegion() = default; @@ -95,6 +101,9 @@ namespace AZ virtual void SetProfilerEnabled(bool enabled) = 0; virtual bool IsProfilerEnabled() const = 0 ; + + //! Used by AZ_ATOM_PROFILE_DYNAMIC to create GroupRegionNames with known lifetimes. + virtual const CachedTimeRegion::GroupRegionName& InsertDynamicName(const char* groupName, const AZStd::string& regionName) = 0; }; } // namespace RPI @@ -120,3 +129,10 @@ namespace AZ #define AZ_ATOM_PROFILE_FUNCTION(groupName, regionName) \ AZ_TRACE_METHOD(); \ AZ_ATOM_PROFILE_TIME_GROUP_REGION(groupName, regionName) \ + +//! Macro that allows for region names to be submitted at runtime. Use sparingly - this acquires a lock and allocates new objects within a map. +#define AZ_ATOM_PROFILE_DYNAMIC(groupName, regionName) \ + static_assert(AZStd::is_convertible_v, "Runtime group names are not allowed, use a static string literal instead."); \ + const AZ::RHI::CachedTimeRegion::GroupRegionName& AZ_JOIN(groupRegionName, __LINE__) = \ + AZ::RHI::CpuProfiler::Get()->InsertDynamicName(groupName, regionName); \ + AZ::RHI::TimeRegion AZ_JOIN(timeRegion, __LINE__)(&AZ_JOIN(groupRegionName, __LINE__)); diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfilerImpl.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfilerImpl.h index 7d3b0c5b81..2e4ca67db8 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfilerImpl.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfilerImpl.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -114,9 +115,11 @@ namespace AZ bool IsContinuousCaptureInProgress() const final override; void SetProfilerEnabled(bool enabled) final override; bool IsProfilerEnabled() const final override; + const CachedTimeRegion::GroupRegionName& InsertDynamicName(const char* groupName, const AZStd::string& regionName) final override; private: static constexpr AZStd::size_t MaxFramesToSave = 2 * 60 * 120; // 2 minutes of 120fps + static constexpr AZStd::size_t MaxRegionStringPoolSize = 16384; // Max amount of unique strings to save in the pool before throwing warnings. // Lazily create and register the local thread data void RegisterThreadStorage(); @@ -129,6 +132,15 @@ namespace AZ AZStd::vector, AZ::OSStdAllocator> m_registeredThreads; AZStd::mutex m_threadRegisterMutex; + // Pool for GroupRegionNames that are generated at runtime through AZ_ATOM_PROFILE_DYNAMIC. Each unique + // combination of group name and region name submitted will be stored in this pool to emulate static lifetime. + AZStd::unordered_set m_dynamicGroupRegionNamePool; + + // String pool for storing region names submitted at runtime. Each call to AZ_ATOM_PROFILE_DYNAMIC will either construct + // a string in this pool or use an already-existing entry. + AZStd::unordered_set m_regionNameStringPool; + AZStd::mutex m_dynamicNameMutex; + // Thread local storage, gets lazily allocated when a thread is created static thread_local CpuTimingLocalStorage* ms_threadLocalStorage; diff --git a/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp b/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp index cdfd4ac469..d41b5d656e 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp @@ -74,6 +74,20 @@ namespace AZ { } + AZStd::size_t CachedTimeRegion::GroupRegionName::Hash::operator()(const CachedTimeRegion::GroupRegionName& name) const + { + AZStd::size_t seed = 0; + AZStd::hash_combine(seed, name.m_groupName); + AZStd::hash_combine(seed, name.m_regionName); + return seed; + } + + bool CachedTimeRegion::GroupRegionName::operator==(const GroupRegionName& other) const + { + return (m_groupName == other.m_groupName) && (m_regionName == other.m_regionName); + } + + // --- CpuProfilerImpl --- void CpuProfilerImpl::Init() @@ -218,6 +232,19 @@ namespace AZ return m_enabled; } + const CachedTimeRegion::GroupRegionName& CpuProfilerImpl::InsertDynamicName(const char* groupName, const AZStd::string& regionName) + { + AZStd::scoped_lock lock(m_dynamicNameMutex); + AZ_Warning("CpuProfiler", m_regionNameStringPool.size() < MaxRegionStringPoolSize, + "Stored dynamic region names are accumulating. Consider removing a AZ_ATOM_PROFILE_DYNAMIC invocation."); + auto [regionNameItr, wasRegionInserted] = m_regionNameStringPool.insert(regionName); + + CachedTimeRegion::GroupRegionName newGroupRegionName(groupName, regionNameItr->c_str()); + auto [groupRegionNameItr, wasGroupRegionInserted] = m_dynamicGroupRegionNamePool.insert(newGroupRegionName); + + return *groupRegionNameItr; + } + void CpuProfilerImpl::OnSystemTick() { if (!m_enabled) From 1c7f71f93a5bd42700f7f750d97ce50424048b13 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Mon, 16 Aug 2021 12:13:32 -0500 Subject: [PATCH 66/70] Updated Atom automated test that uses the PostFX Radius Weight Modifier. Signed-off-by: Chris Galvan --- ...ydra_AtomEditorComponents_AddedToEntity.py | 4 +-- .../atom_renderer/test_Atom_MainSuite.py | 26 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_AtomEditorComponents_AddedToEntity.py b/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_AtomEditorComponents_AddedToEntity.py index b4031d2ffa..cd10caf57b 100644 --- a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_AtomEditorComponents_AddedToEntity.py +++ b/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_AtomEditorComponents_AddedToEntity.py @@ -206,8 +206,8 @@ def run(): # PostFX Layer Component ComponentTests("PostFX Layer") - # Radius Weight Modifier Component - ComponentTests("Radius Weight Modifier") + # PostFX Radius Weight Modifier Component + ComponentTests("PostFX Radius Weight Modifier") # Light Component ComponentTests("Light") diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_MainSuite.py b/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_MainSuite.py index be75801b63..55c049b929 100644 --- a/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_MainSuite.py +++ b/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_MainSuite.py @@ -32,7 +32,7 @@ class TestAtomEditorComponentsMain(object): Tests the following Atom components and verifies all "expected_lines" appear in Editor.log: 1. Display Mapper 2. Light - 3. Radius Weight Modifier + 3. PostFX Radius Weight Modifier 4. PostFX Layer 5. Physical Sky 6. Global Skylight (IBL) @@ -126,18 +126,18 @@ class TestAtomEditorComponentsMain(object): "PostFX Layer_test: Entity deleted: True", "PostFX Layer_test: UNDO entity deletion works: True", "PostFX Layer_test: REDO entity deletion works: True", - # Radius Weight Modifier Component - "Radius Weight Modifier Entity successfully created", - "Radius Weight Modifier_test: Component added to the entity: True", - "Radius Weight Modifier_test: Component removed after UNDO: True", - "Radius Weight Modifier_test: Component added after REDO: True", - "Radius Weight Modifier_test: Entered game mode: True", - "Radius Weight Modifier_test: Exit game mode: True", - "Radius Weight Modifier_test: Entity is hidden: True", - "Radius Weight Modifier_test: Entity is shown: True", - "Radius Weight Modifier_test: Entity deleted: True", - "Radius Weight Modifier_test: UNDO entity deletion works: True", - "Radius Weight Modifier_test: REDO entity deletion works: True", + # PostFX Radius Weight Modifier Component + "PostFX Radius Weight Modifier Entity successfully created", + "PostFX Radius Weight Modifier_test: Component added to the entity: True", + "PostFX Radius Weight Modifier_test: Component removed after UNDO: True", + "PostFX Radius Weight Modifier_test: Component added after REDO: True", + "PostFX Radius Weight Modifier_test: Entered game mode: True", + "PostFX Radius Weight Modifier_test: Exit game mode: True", + "PostFX Radius Weight Modifier_test: Entity is hidden: True", + "PostFX Radius Weight Modifier_test: Entity is shown: True", + "PostFX Radius Weight Modifier_test: Entity deleted: True", + "PostFX Radius Weight Modifier_test: UNDO entity deletion works: True", + "PostFX Radius Weight Modifier_test: REDO entity deletion works: True", # Light Component "Light Entity successfully created", "Light_test: Component added to the entity: True", From b88a7faf642e102282b45021d91ea50d7ef18cc3 Mon Sep 17 00:00:00 2001 From: AMZN-stankowi <4838196+AMZN-stankowi@users.noreply.github.com> Date: Mon, 16 Aug 2021 10:18:45 -0700 Subject: [PATCH 67/70] Fixed issues with blend shape animations (#3080) Duplicate blend shape animations are now handled correctly. Invalid animation targets are now an error instead of a crash in the builder. Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com> --- .../SDKWrapper/AssImpSceneWrapper.cpp | 3 + .../Importers/AssImpAnimationImporter.cpp | 32 ++++++- .../Importers/AssImpBlendShapeImporter.cpp | 87 ++++++++++++++++--- 3 files changed, 107 insertions(+), 15 deletions(-) diff --git a/Code/Tools/SceneAPI/SDKWrapper/AssImpSceneWrapper.cpp b/Code/Tools/SceneAPI/SDKWrapper/AssImpSceneWrapper.cpp index 0680b41eca..12aefca00c 100644 --- a/Code/Tools/SceneAPI/SDKWrapper/AssImpSceneWrapper.cpp +++ b/Code/Tools/SceneAPI/SDKWrapper/AssImpSceneWrapper.cpp @@ -70,6 +70,9 @@ namespace AZ // This results in the loss of the offset matrix data for nodes without a mesh which is required for the Transform Importer. m_importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, false); m_importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, false); + // The remove empty bones flag is on by default, but doesn't do anything internal to AssImp right now. + // This is here as a bread crumb to save others times investigating issues with empty bones. + // m_importer.SetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, false); m_sceneFileName = fileName; m_assImpScene = m_importer.ReadFile(fileName, aiProcess_Triangulate //Triangulates all faces of all meshes diff --git a/Code/Tools/SceneAPI/SceneBuilder/Importers/AssImpAnimationImporter.cpp b/Code/Tools/SceneAPI/SceneBuilder/Importers/AssImpAnimationImporter.cpp index 150a50138e..97b5960a8d 100644 --- a/Code/Tools/SceneAPI/SceneBuilder/Importers/AssImpAnimationImporter.cpp +++ b/Code/Tools/SceneAPI/SceneBuilder/Importers/AssImpAnimationImporter.cpp @@ -147,7 +147,9 @@ namespace AZ SerializeContext* serializeContext = azrtti_cast(context); if (serializeContext) { - serializeContext->Class()->Version(5); // [LYN-4226] Invert PostRotation matrix in animation chains + // Revision 5: [LYN-4226] Invert PostRotation matrix in animation chains + // Revision 6: Handle duplicate blend shape animations + serializeContext->Class()->Version(6); } } @@ -631,6 +633,15 @@ namespace AZ for (const auto& [meshIdx, keys] : valueToKeyDataMap) { + + if (static_cast(meshIdx) >= mesh->mNumAnimMeshes) + { + AZ_Error( + "AnimationImporter", false, + "Mesh %s has an animation mesh index reference of %d, but only has %d animation meshes. Skipping importing this. This is an error in the source scene file that should be corrected.", + mesh->mName.C_Str(), meshIdx, mesh->mNumAnimMeshes); + continue; + } AZStd::shared_ptr morphAnimNode = AZStd::make_shared(); @@ -656,12 +667,29 @@ namespace AZ morphAnimNode->AddKeyFrame(weight); } + // Some DCC tools, like Maya, include a full path separated by '.' in the node names. + // For example, "cone_skin_blendShapeNode.cone_squash" + // Downstream processing doesn't want anything but the last part of that node name, + // so find the last '.' and remove anything before it. const size_t dotIndex = nodeName.find_last_of('.'); nodeName = nodeName.substr(dotIndex + 1); morphAnimNode->SetBlendShapeName(nodeName.data()); - AZStd::string animNodeName(AZStd::string::format("%s_%s", s_animationNodeName, nodeName.data())); + // Duplicates can exist if an anim mesh had a name with a suffix like .001, in that case + // AssImp will strip off that suffix. Note that this behavior is separate from the + // scan for a period in the node name that came before this. + AZStd::string originalNodeName(AZStd::string::format("%s_%s", s_animationNodeName, nodeName.data())); + AZStd::string animNodeName(originalNodeName); + if (RenamedNodesMap::SanitizeNodeName( + animNodeName, context.m_scene.GetGraph(), context.m_currentGraphPosition, originalNodeName.c_str())) + { + AZ_Warning( + "AnimationImporter", false, + "Duplicate animations were found with the name %s on mesh %s. The duplicate will be named %s.", + originalNodeName.c_str(), mesh->mName.C_Str(), animNodeName.c_str()); + } + Containers::SceneGraph::NodeIndex addNode = context.m_scene.GetGraph().AddChild( context.m_currentGraphPosition, animNodeName.c_str(), AZStd::move(morphAnimNode)); context.m_scene.GetGraph().MakeEndPoint(addNode); diff --git a/Code/Tools/SceneAPI/SceneBuilder/Importers/AssImpBlendShapeImporter.cpp b/Code/Tools/SceneAPI/SceneBuilder/Importers/AssImpBlendShapeImporter.cpp index e8eb5ecf68..8e447f9d79 100644 --- a/Code/Tools/SceneAPI/SceneBuilder/Importers/AssImpBlendShapeImporter.cpp +++ b/Code/Tools/SceneAPI/SceneBuilder/Importers/AssImpBlendShapeImporter.cpp @@ -40,7 +40,9 @@ namespace AZ SerializeContext* serializeContext = azrtti_cast(context); if (serializeContext) { - serializeContext->Class()->Version(3); // LYN-2576 + // Revision 3: Fixed an issue where jack.fbx was failing to process + // Revision 4: Handle duplicate blend shape animations + serializeContext->Class()->Version(4); } } @@ -80,7 +82,32 @@ namespace AZ // AssImp separates meshes that have multiple materials. // This code re-combines them to match previous FBX SDK behavior, // so they can be separated by engine code instead. - AZStd::map>> animToMeshToAnimMeshIndices; + // Can't de-dupe nodes in the first loop because we can't generate names until we create nodes later. + // Because meshes are split on material at this point and need to be recombined, we can be in a position where + // There is a legit duped anim mesh that needs to be combined based on the outer non-anim mesh, + // or this is a duplicately named anim mesh that needs to be de-duped. There is also the case where both are true, + // it's a duplicate name and the non-anim mesh has to be deduped. + + // Helper struct to track an anim mesh and its associated mesh. + struct AnimMeshAndSceneMeshIndex + { + AnimMeshAndSceneMeshIndex(const aiAnimMesh* aiAnimMesh, const aiMesh* aiMesh) + : m_aiAnimMesh(aiAnimMesh) + , m_aiMesh(aiMesh) + { + } + const aiAnimMesh* m_aiAnimMesh = nullptr; + const aiMesh* m_aiMesh = nullptr; + }; + + // Helper struct to track all anim meshes at an index for all scene meshes. + struct AnimMeshAndSceneMeshes + { + AZStd::vector m_animMeshAndSceneMeshIndex; + }; + + // Map the animation index to the list of anim meshes at that index, and the mesh associated with those anim meshes. + AZStd::map animMeshIndexToSceneMeshes; for (int nodeMeshIdx = 0; nodeMeshIdx < numMesh; nodeMeshIdx++) { int sceneMeshIdx = context.m_sourceNode.GetAssImpNode()->mMeshes[nodeMeshIdx]; @@ -88,20 +115,57 @@ namespace AZ for (unsigned int animIdx = 0; animIdx < aiMesh->mNumAnimMeshes; animIdx++) { aiAnimMesh* aiAnimMesh = aiMesh->mAnimMeshes[animIdx]; - animToMeshToAnimMeshIndices[aiAnimMesh->mName.C_Str()].emplace_back(nodeMeshIdx, animIdx); + + // This code executes if: + // A mesh in the FBX file had multiple materials and blend shapes. + // This means that AssImp splits that mesh to one material per mesh. + // AssImp creates a set of anim meshes for each mesh based on that split. + // This verifies that those anim mesh arrays are in the same order across all split meshes, if it fails + // it means this logic needs to be updated, but it also catches that here earlier in an obvious way, + // instead of failing later in a harder to track way. + if (animMeshIndexToSceneMeshes.contains(animIdx)) + { + const AnimMeshAndSceneMeshIndex& firstExistingAnim( + animMeshIndexToSceneMeshes[animIdx].m_animMeshAndSceneMeshIndex[0]); + if (strcmp( + firstExistingAnim.m_aiAnimMesh->mName.C_Str(), + aiAnimMesh->mName.C_Str()) != 0) + { + AZ_Error( + Utilities::ErrorWindow, false, + "Meshes %s and %s on node %s have mismatched animations %s and %s at index %d. This can be resolved by " + "either manually separating meshes by material in the source scene file, or by updating this logic to " + "handle out of order animation indices.", + firstExistingAnim.m_aiMesh->mName.C_Str(), + aiMesh->mName.C_Str(), + context.m_sourceNode.GetName(), + firstExistingAnim.m_aiAnimMesh->mName.C_Str(), + aiAnimMesh->mName.C_Str(), animIdx); + return Events::ProcessingResult::Failure; + } + } + + animMeshIndexToSceneMeshes[animIdx].m_animMeshAndSceneMeshIndex.emplace_back( + AnimMeshAndSceneMeshIndex(aiAnimMesh, aiMesh)); } } - for (const auto& animToMeshIndex : animToMeshToAnimMeshIndices) + for (const auto& animMeshToSceneMeshes : animMeshIndexToSceneMeshes) { AZStd::shared_ptr blendShapeData = AZStd::make_shared(); + if (animMeshToSceneMeshes.second.m_animMeshAndSceneMeshIndex.size() == 0) + { + AZ_Error(Utilities::ErrorWindow, false, "Blend shape animations were expected but missing on node %s.", + context.m_sourceNode.GetName()); + return Events::ProcessingResult::Failure; + } // Some DCC tools, like Maya, include a full path separated by '.' in the node names. // For example, "cone_skin_blendShapeNode.cone_squash" // Downstream processing doesn't want anything but the last part of that node name, // so find the last '.' and remove anything before it. - AZStd::string nodeName(animToMeshIndex.first); + AZStd::string nodeName(animMeshToSceneMeshes.second.m_animMeshAndSceneMeshIndex[0].m_aiAnimMesh->mName.C_Str()); size_t dotIndex = nodeName.rfind('.'); if (dotIndex != AZStd::string::npos) { @@ -109,12 +173,11 @@ namespace AZ } int vertexOffset = 0; RenamedNodesMap::SanitizeNodeName(nodeName, context.m_scene.GetGraph(), context.m_currentGraphPosition, "BlendShape"); - AZ_TraceContext("Blend shape name", nodeName); - for (const auto& meshIndex : animToMeshIndex.second) + + for (const auto& animMeshAndSceneIndex : animMeshToSceneMeshes.second.m_animMeshAndSceneMeshIndex) { - int sceneMeshIdx = context.m_sourceNode.GetAssImpNode()->mMeshes[meshIndex.first]; - const aiMesh* aiMesh = context.m_sourceScene.GetAssImpScene()->mMeshes[sceneMeshIdx]; - const aiAnimMesh* aiAnimMesh = aiMesh->mAnimMeshes[meshIndex.second]; + const aiAnimMesh* aiAnimMesh = animMeshAndSceneIndex.m_aiAnimMesh; + const aiMesh* aiMesh = animMeshAndSceneIndex.m_aiMesh; AZStd::bitset uvSetUsedFlags; for (AZ::u8 uvSetIndex = 0; uvSetIndex < SceneData::GraphData::BlendShapeData::MaxNumUVSets; ++uvSetIndex) @@ -199,6 +262,7 @@ namespace AZ face.mNumIndices); continue; } + for (unsigned int idx = 0; idx < face.mNumIndices; ++idx) { blendFace.vertexIndex[idx] = face.mIndices[idx] + vertexOffset; @@ -207,11 +271,8 @@ namespace AZ blendShapeData->AddFace(blendFace); } vertexOffset += aiMesh->mNumVertices; - - } - // Report problem if no vertex or face converted to MeshData if (blendShapeData->GetVertexCount() <= 0 || blendShapeData->GetFaceCount() <= 0) { From d6b268e84e54b3d606e129bf346010b88be4b1ba Mon Sep 17 00:00:00 2001 From: amzn-phist <52085794+amzn-phist@users.noreply.github.com> Date: Mon, 16 Aug 2021 12:41:24 -0500 Subject: [PATCH 68/70] Remove ResourceSelectorHost and clean up/refactor related bits (#3050) * Sever dependency on legacy resource selector host Audio resource selectors (browse dialogs) no longer need to be registered with the legacy IResourceSelectorHost system. Set up a new EBus specifically to handle browse button presses and directly invokes the dialog. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Hook up legacy audio control selector to new EBus Remaining use of legacy audio selectors (trackview) need to be able to bypass ResourceSelectorHost now. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Removes ResourceSelectorHost and legacy selectors This removes various Variable types that were tied to resource selectors, such as GeomCache, Model, Animation, File. Removes the ResourceSelectorHost completely. The two things that still appeared to have selectors in TrackView are Audio Controls and Texture. Fixed the audio control selector to work via EBus and the Texture selector didn't seem to work at all, but left it in as it was. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Make the default audio selector return old value Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Fix some signed/unsigned comparison warnings Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Remove deleted function from Editor Mock Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Change audio selector api to use string_view Per feedback. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> --- .../ReflectedPropertyControl/PropertyCtrl.cpp | 3 - .../PropertyGenericCtrl.cpp | 10 -- .../PropertyGenericCtrl.h | 10 -- .../PropertyResourceCtrl.cpp | 78 ++++----- .../ReflectedPropertiesPanel.cpp | 93 ---------- .../ReflectedPropertiesPanel.h | 46 ----- .../ReflectedPropertyItem.cpp | 10 -- .../ReflectedPropertyControl/ReflectedVar.cpp | 14 -- .../ReflectedPropertyControl/ReflectedVar.h | 25 --- .../ReflectedVarWrapper.cpp | 21 +-- .../ReflectedVarWrapper.h | 14 -- Code/Editor/EditorPanelUtils.cpp | 4 +- Code/Editor/IEditor.h | 2 - Code/Editor/IEditorImpl.cpp | 2 - Code/Editor/IEditorImpl.h | 2 - Code/Editor/IEditorPanelUtils.h | 2 +- Code/Editor/Include/IResourceSelectorHost.h | 135 --------------- Code/Editor/Lib/Tests/IEditorMock.h | 1 - .../ComponentEntityEditorPlugin.cpp | 3 - .../SandboxIntegration.cpp | 11 -- .../SandboxIntegration.h | 1 - Code/Editor/ResourceSelectorHost.cpp | 163 ------------------ Code/Editor/ResourceSelectorHost.h | 18 -- Code/Editor/Util/Variable.cpp | 2 +- Code/Editor/Util/Variable.h | 6 - Code/Editor/Util/VariablePropertyType.cpp | 33 ---- Code/Editor/Util/VariablePropertyType.h | 6 - Code/Editor/editor_lib_files.cmake | 8 - .../API/ToolsApplicationAPI.h | 3 - .../UI/PropertyEditor/PropertyAudioCtrl.cpp | 19 +- .../UI/PropertyEditor/PropertyAudioCtrl.h | 21 +++ .../PropertyEditor/PropertyAudioCtrlTypes.h | 10 +- .../Editor/ATLControlsResourceDialog.cpp | 2 + .../Editor/AudioControlsEditorPlugin.cpp | 3 - .../Source/Editor/AudioControlsEditorPlugin.h | 4 +- .../Source/Editor/AudioResourceSelectors.cpp | 105 ++++------- .../Source/Editor/AudioResourceSelectors.h | 11 +- 37 files changed, 125 insertions(+), 776 deletions(-) delete mode 100644 Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertiesPanel.cpp delete mode 100644 Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertiesPanel.h delete mode 100644 Code/Editor/Include/IResourceSelectorHost.h delete mode 100644 Code/Editor/ResourceSelectorHost.cpp delete mode 100644 Code/Editor/ResourceSelectorHost.h diff --git a/Code/Editor/Controls/ReflectedPropertyControl/PropertyCtrl.cpp b/Code/Editor/Controls/ReflectedPropertyControl/PropertyCtrl.cpp index bf87f2017d..c228fbda09 100644 --- a/Code/Editor/Controls/ReflectedPropertyControl/PropertyCtrl.cpp +++ b/Code/Editor/Controls/ReflectedPropertyControl/PropertyCtrl.cpp @@ -10,7 +10,6 @@ // Editor #include "PropertyCtrl.h" -#include "PropertyAnimationCtrl.h" #include "PropertyResourceCtrl.h" #include "PropertyGenericCtrl.h" #include "PropertyMiscCtrl.h" @@ -22,9 +21,7 @@ void RegisterReflectedVarHandlers() if (!registered) { registered = true; - EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew AnimationPropertyWidgetHandler()); EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew FileResourceSelectorWidgetHandler()); - EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew ReverbPresetPropertyHandler()); EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew SequencePropertyHandler()); EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew SequenceIdPropertyHandler()); EBUS_EVENT(AzToolsFramework::PropertyTypeRegistrationMessages::Bus, RegisterPropertyType, aznew LocalStringPropertyHandler()); diff --git a/Code/Editor/Controls/ReflectedPropertyControl/PropertyGenericCtrl.cpp b/Code/Editor/Controls/ReflectedPropertyControl/PropertyGenericCtrl.cpp index a2c66b8b10..8ff83dd894 100644 --- a/Code/Editor/Controls/ReflectedPropertyControl/PropertyGenericCtrl.cpp +++ b/Code/Editor/Controls/ReflectedPropertyControl/PropertyGenericCtrl.cpp @@ -73,16 +73,6 @@ void GenericPopupPropertyEditor::SetPropertyType(PropertyType type) m_propertyType = type; } -void ReverbPresetPropertyEditor::onEditClicked() -{ - CSelectEAXPresetDlg PresetDlg(this); - PresetDlg.SetCurrPreset(GetValue()); - if (PresetDlg.exec() == QDialog::Accepted) - { - SetValue(PresetDlg.GetCurrPreset()); - } -} - void SequencePropertyEditor::onEditClicked() { CSelectSequenceDialog gtDlg(this); diff --git a/Code/Editor/Controls/ReflectedPropertyControl/PropertyGenericCtrl.h b/Code/Editor/Controls/ReflectedPropertyControl/PropertyGenericCtrl.h index 2296773f0a..b6b14cf125 100644 --- a/Code/Editor/Controls/ReflectedPropertyControl/PropertyGenericCtrl.h +++ b/Code/Editor/Controls/ReflectedPropertyControl/PropertyGenericCtrl.h @@ -96,15 +96,6 @@ public: } }; -class ReverbPresetPropertyEditor - : public GenericPopupPropertyEditor -{ -public: - ReverbPresetPropertyEditor(QWidget* pParent = nullptr) - : GenericPopupPropertyEditor(pParent){} - void onEditClicked() override; -}; - class MissionObjPropertyEditor : public GenericPopupPropertyEditor { @@ -155,7 +146,6 @@ public: // So we use our own #define CONST_AZ_CRC(name, value) AZ::u32(value) -using ReverbPresetPropertyHandler = GenericPopupWidgetHandler; using MissionObjPropertyHandler = GenericPopupWidgetHandler; using SequencePropertyHandler = GenericPopupWidgetHandler; using SequenceIdPropertyHandler = GenericPopupWidgetHandler; diff --git a/Code/Editor/Controls/ReflectedPropertyControl/PropertyResourceCtrl.cpp b/Code/Editor/Controls/ReflectedPropertyControl/PropertyResourceCtrl.cpp index d3ae6aaecf..c5ccc599d6 100644 --- a/Code/Editor/Controls/ReflectedPropertyControl/PropertyResourceCtrl.cpp +++ b/Code/Editor/Controls/ReflectedPropertyControl/PropertyResourceCtrl.cpp @@ -17,9 +17,9 @@ // AzToolsFramework #include #include +#include // Editor -#include "IResourceSelectorHost.h" #include "Controls/QToolTipWidget.h" #include "Controls/BitmapToolTip.h" @@ -35,8 +35,8 @@ BrowseButton::BrowseButton(PropertyType type, QWidget* parent /*= nullptr*/) void BrowseButton::SetPathAndEmit(const QString& path) { - //only emit if path changes, except for ePropertyGeomCache. Old property control - if (path != m_path || m_propertyType == ePropertyGeomCache) + //only emit if path changes. Old property control + if (path != m_path) { m_path = path; emit PathChanged(m_path); @@ -78,21 +78,6 @@ private: // Filters for texture. selection = AssetSelectionModel::AssetGroupSelection("Texture"); } - else if (m_propertyType == ePropertyModel) - { - // Filters for models. - selection = AssetSelectionModel::AssetGroupSelection("Geometry"); - } - else if (m_propertyType == ePropertyGeomCache) - { - // Filters for geom caches. - selection = AssetSelectionModel::AssetTypeSelection("Geom Cache"); - } - else if (m_propertyType == ePropertyFile) - { - // Filters for files. - selection = AssetSelectionModel::AssetTypeSelection("File"); - } else { return; @@ -106,14 +91,7 @@ private: switch (m_propertyType) { case ePropertyTexture: - case ePropertyModel: newPath.replace("\\\\", "/"); - } - switch (m_propertyType) - { - case ePropertyTexture: - case ePropertyModel: - case ePropertyFile: if (newPath.size() > MAX_PATH) { newPath.resize(MAX_PATH); @@ -125,26 +103,51 @@ private: } }; -class ResourceSelectorButton +class AudioControlSelectorButton : public BrowseButton { public: - AZ_CLASS_ALLOCATOR(ResourceSelectorButton, AZ::SystemAllocator, 0); + AZ_CLASS_ALLOCATOR(AudioControlSelectorButton, AZ::SystemAllocator, 0); - ResourceSelectorButton(PropertyType type, QWidget* pParent = nullptr) + AudioControlSelectorButton(PropertyType type, QWidget* pParent = nullptr) : BrowseButton(type, pParent) { - setToolTip(tr("Select resource")); + setToolTip(tr("Select Audio Control")); } private: void OnClicked() override { - SResourceSelectorContext x; - x.parentWidget = this; - x.typeName = Prop::GetPropertyTypeToResourceType(m_propertyType); - QString newPath = GetIEditor()->GetResourceSelectorHost()->SelectResource(x, m_path); - SetPathAndEmit(newPath); + AZStd::string resourceResult; + auto ConvertLegacyAudioPropertyType = [](const PropertyType type) -> AzToolsFramework::AudioPropertyType + { + switch (type) + { + case ePropertyAudioTrigger: + return AzToolsFramework::AudioPropertyType::Trigger; + case ePropertyAudioRTPC: + return AzToolsFramework::AudioPropertyType::Rtpc; + case ePropertyAudioSwitch: + return AzToolsFramework::AudioPropertyType::Switch; + case ePropertyAudioSwitchState: + return AzToolsFramework::AudioPropertyType::SwitchState; + case ePropertyAudioEnvironment: + return AzToolsFramework::AudioPropertyType::Environment; + case ePropertyAudioPreloadRequest: + return AzToolsFramework::AudioPropertyType::Preload; + default: + return AzToolsFramework::AudioPropertyType::NumTypes; + } + }; + + auto propType = ConvertLegacyAudioPropertyType(m_propertyType); + if (propType != AzToolsFramework::AudioPropertyType::NumTypes) + { + AzToolsFramework::AudioControlSelectorRequestBus::EventResult( + resourceResult, propType, &AzToolsFramework::AudioControlSelectorRequestBus::Events::SelectResource, + AZStd::string_view{ m_path.toUtf8().constData() }); + SetPathAndEmit(QString{ resourceResult.c_str() }); + } } }; @@ -235,18 +238,13 @@ void FileResourceSelectorWidget::SetPropertyType(PropertyType type) AddButton(new TextureEditButton); m_previewToolTip.reset(new CBitmapToolTip); break; - case ePropertyModel: - case ePropertyGeomCache: case ePropertyAudioTrigger: case ePropertyAudioSwitch: case ePropertyAudioSwitchState: case ePropertyAudioRTPC: case ePropertyAudioEnvironment: case ePropertyAudioPreloadRequest: - AddButton(new ResourceSelectorButton(type)); - break; - case ePropertyFile: - AddButton(new FileBrowseButton(type)); + AddButton(new AudioControlSelectorButton(type)); break; default: break; diff --git a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertiesPanel.cpp b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertiesPanel.cpp deleted file mode 100644 index 8651db7e96..0000000000 --- a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertiesPanel.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - - -// Description : implementation file - -#include "EditorDefs.h" - -#include "ReflectedPropertiesPanel.h" - -///////////////////////////////////////////////////////////////////////////// -// ReflectedPropertiesPanel dialog - - -ReflectedPropertiesPanel::ReflectedPropertiesPanel(QWidget* pParent) - : ReflectedPropertyControl(pParent) -{ -} - -////////////////////////////////////////////////////////////////////////// -void ReflectedPropertiesPanel::DeleteVars() -{ - ClearVarBlock(); - m_updateCallbacks.clear(); - m_varBlock = nullptr; -} - -////////////////////////////////////////////////////////////////////////// -void ReflectedPropertiesPanel::SetVarBlock(class CVarBlock* vb, ReflectedPropertyControl::UpdateVarCallback* updCallback, const char* category) -{ - assert(vb); - - m_varBlock = vb; - - RemoveAllItems(); - m_varBlock = vb; - AddVarBlock(m_varBlock, category); - - SetUpdateCallback(AZStd::bind(&ReflectedPropertiesPanel::OnPropertyChanged, this, AZStd::placeholders::_1)); - - // When new object set all previous callbacks freed. - m_updateCallbacks.clear(); - if (updCallback) - { - stl::push_back_unique(m_updateCallbacks, updCallback); - } -} - -////////////////////////////////////////////////////////////////////////// -void ReflectedPropertiesPanel::AddVars(CVarBlock* vb, ReflectedPropertyControl::UpdateVarCallback* updCallback, const char* category) -{ - assert(vb); - - bool bNewBlock = false; - // Make a clone of properties. - if (!m_varBlock) - { - RemoveAllItems(); - m_varBlock = vb->Clone(true); - AddVarBlock(m_varBlock, category); - bNewBlock = true; - } - m_varBlock->Wire(vb); - - if (bNewBlock) - { - SetUpdateCallback(AZStd::bind(&ReflectedPropertiesPanel::OnPropertyChanged, this, AZStd::placeholders::_1)); - - // When new object set all previous callbacks freed. - m_updateCallbacks.clear(); - } - - if (updCallback) - { - stl::push_back_unique(m_updateCallbacks, updCallback); - } -} - -void ReflectedPropertiesPanel::OnPropertyChanged(IVariable* pVar) -{ - std::list::iterator iter; - for (iter = m_updateCallbacks.begin(); iter != m_updateCallbacks.end(); ++iter) - { - (*iter)->operator()(pVar); - } -} - - diff --git a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertiesPanel.h b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertiesPanel.h deleted file mode 100644 index cd551c63e2..0000000000 --- a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertiesPanel.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#ifndef CRYINCLUDE_EDITOR_REFLECTEDPROPERTIESPANEL_H -#define CRYINCLUDE_EDITOR_REFLECTEDPROPERTIESPANEL_H - -#pragma once - -#include "Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.h" -#include "Util/Variable.h" - -///////////////////////////////////////////////////////////////////////////// -// ReflectedPropertiesPanel dialog - -AZ_PUSH_DISABLE_DLL_EXPORT_BASECLASS_WARNING -//This class is a port of ReflectedPropertiesPanel to use the ReflectedPropertyControl -class SANDBOX_API ReflectedPropertiesPanel - : public ReflectedPropertyControl -{ -AZ_POP_DISABLE_DLL_EXPORT_BASECLASS_WARNING -public: - ReflectedPropertiesPanel(QWidget* pParent = nullptr); // standard constructor - - void DeleteVars(); - void AddVars(class CVarBlock* vb, ReflectedPropertyControl::UpdateVarCallback* func = nullptr, const char* category = nullptr); - - void SetVarBlock(class CVarBlock* vb, ReflectedPropertyControl::UpdateVarCallback* func = nullptr, const char* category = nullptr); - -protected: - void OnPropertyChanged(IVariable* pVar); - -protected: - AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING - TSmartPtr m_varBlock; - - std::list m_updateCallbacks; - AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING -}; - - -#endif // CRYINCLUDE_EDITOR_REFLECTEDPROPERTIESPANEL_H diff --git a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyItem.cpp b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyItem.cpp index 5a9d61be42..303f86d270 100644 --- a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyItem.cpp +++ b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyItem.cpp @@ -255,9 +255,6 @@ void ReflectedPropertyItem::SetVariable(IVariable *var) case ePropertySelection: m_reflectedVarAdapter = new ReflectedVarEnumAdapter; break; - case ePropertyAnimation: - m_reflectedVarAdapter = new ReflectedVarAnimationAdapter; - break; case ePropertyColor: m_reflectedVarAdapter = new ReflectedVarColorAdapter; break; @@ -265,7 +262,6 @@ void ReflectedPropertyItem::SetVariable(IVariable *var) m_reflectedVarAdapter = new ReflectedVarUserAdapter; break; case ePropertyEquip: - case ePropertyReverbPreset: case ePropertyGameToken: case ePropertyMissionObj: case ePropertySequence: @@ -276,15 +272,12 @@ void ReflectedPropertyItem::SetVariable(IVariable *var) m_reflectedVarAdapter = new ReflectedVarGenericPropertyAdapter(desc.m_type); break; case ePropertyTexture: - case ePropertyModel: - case ePropertyGeomCache: case ePropertyAudioTrigger: case ePropertyAudioSwitch: case ePropertyAudioSwitchState: case ePropertyAudioRTPC: case ePropertyAudioEnvironment: case ePropertyAudioPreloadRequest: - case ePropertyFile: m_reflectedVarAdapter = new ReflectedVarResourceAdapter; break; case ePropertyFloatCurve: @@ -569,7 +562,6 @@ void ReflectedPropertyItem::SetValue(const QString& sValue, bool bRecordUndo, bo break; case ePropertyTexture: - case ePropertyModel: value.replace('\\', '/'); break; } @@ -578,8 +570,6 @@ void ReflectedPropertyItem::SetValue(const QString& sValue, bool bRecordUndo, bo switch (m_type) { case ePropertyTexture: - case ePropertyModel: - case ePropertyFile: if (value.length() >= MAX_PATH) { value = value.left(MAX_PATH); diff --git a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVar.cpp b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVar.cpp index 5b9c5b8063..263c17a8bb 100644 --- a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVar.cpp +++ b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVar.cpp @@ -31,12 +31,6 @@ void ReflectedVarInit::setupReflection(AZ::SerializeContext* serializeContext) ->Field("description", &CReflectedVar::m_description) ->Field("varName", &CReflectedVar::m_varName); - serializeContext->Class () - ->Version(1) - ->Field("animation", &CReflectedVarAnimation::m_animation) - ->Field("entityID", &CReflectedVarAnimation::m_entityID) - ; - serializeContext->Class () ->Version(1) ->Field("path", &CReflectedVarResource::m_path) @@ -76,12 +70,6 @@ void ReflectedVarInit::setupReflection(AZ::SerializeContext* serializeContext) AZ::EditContext* ec = serializeContext->GetEditContext(); if (ec) { - ec->Class< CReflectedVarAnimation >("VarAnimation", "Animation") - ->ClassElement(AZ::Edit::ClassElements::EditorData, "") - ->Attribute(AZ::Edit::Attributes::NameLabelOverride, &CReflectedVarAnimation::varName) - ->Attribute(AZ::Edit::Attributes::DescriptionTextOverride, &CReflectedVarAnimation::description) - ; - ec->Class< CReflectedVarResource >("VarResource", "Resource") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::NameLabelOverride, &CReflectedVarResource::varName) @@ -284,8 +272,6 @@ AZ::u32 CReflectedVarGenericProperty::handler() return AZ_CRC("ePropertyShader", 0xc40932f1); case ePropertyEquip: return AZ_CRC("ePropertyEquip", 0x66ffd290); - case ePropertyReverbPreset: - return AZ_CRC("ePropertyReverbPreset", 0x51469f38); case ePropertyDeprecated0: return AZ_CRC("ePropertyCustomAction", 0x4ffa5ba5); case ePropertyGameToken: diff --git a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVar.h b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVar.h index 634f2efd3a..a15f8326d1 100644 --- a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVar.h +++ b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVar.h @@ -265,32 +265,8 @@ public: AZ::Vector3 m_color; }; -//Class to hold ePropertyAnimation (IVariable::DT_ANIMATION ) -class CReflectedVarAnimation - : public CReflectedVar -{ -public: - AZ_RTTI(CReflectedVarAnimation, "{635D982E-23EC-463F-8F33-4FC2C19D5673}", CReflectedVar) - - CReflectedVarAnimation(const AZStd::string& name) - : CReflectedVar(name) - , m_entityID(0) - {} - CReflectedVarAnimation() - : m_entityID(0){} - - AZStd::string varName() const { return m_varName; } - AZStd::string description() const { return m_description; } - - AZStd::string m_animation; - AZ::EntityId m_entityID; -}; - //Class to hold: // ePropertyTexture (IVariable::DT_TEXTURE) -// ePropertyMaterial (IVariable::DT_MATERIAL) -// ePropertyModel (IVariable::DT_OBJECT) -// ePropertyGeomCache (IVariable::DT_GEOM_CACHE) // ePropertyAudioTrigger (IVariable::DT_AUDIO_TRIGGER) // ePropertyAudioSwitch (IVariable::DT_AUDIO_SWITCH ) // ePropertyAudioSwitchState (IVariable::DT_AUDIO_SWITCH_STATE) @@ -344,7 +320,6 @@ public: AZStd::vector m_itemDescriptions; }; -//Class to hold ePropertyAnimation (IVariable::DT_ANIMATION ) class CReflectedVarSpline : public CReflectedVar { diff --git a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVarWrapper.cpp b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVarWrapper.cpp index 5639fa95b0..aba346ce6a 100644 --- a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVarWrapper.cpp +++ b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVarWrapper.cpp @@ -392,25 +392,6 @@ void ReflectedVarColorAdapter::SyncIVarToReflectedVar(IVariable *pVariable) -void ReflectedVarAnimationAdapter::SetVariable(IVariable *pVariable) -{ - m_reflectedVar.reset(new CReflectedVarAnimation(pVariable->GetHumanName().toUtf8().data())); - m_reflectedVar->m_description = pVariable->GetDescription().toUtf8().data(); -} - -void ReflectedVarAnimationAdapter::SyncReflectedVarToIVar(IVariable *pVariable) -{ - m_reflectedVar->m_entityID = static_cast(pVariable->GetUserData().value()); - m_reflectedVar->m_animation = pVariable->GetDisplayValue().toUtf8().data(); -} - -void ReflectedVarAnimationAdapter::SyncIVarToReflectedVar(IVariable *pVariable) -{ - pVariable->SetUserData(static_cast(m_reflectedVar->m_entityID)); - pVariable->SetDisplayValue(m_reflectedVar->m_animation.c_str()); - -} - void ReflectedVarResourceAdapter::SetVariable(IVariable *pVariable) { m_reflectedVar.reset(new CReflectedVarResource(pVariable->GetHumanName().toUtf8().data())); @@ -429,7 +410,7 @@ void ReflectedVarResourceAdapter::SyncReflectedVarToIVar(IVariable *pVariable) void ReflectedVarResourceAdapter::SyncIVarToReflectedVar(IVariable *pVariable) { - const bool bForceModified = (m_reflectedVar->m_propertyType == ePropertyGeomCache); + const bool bForceModified = false; pVariable->SetForceModified(bForceModified); pVariable->SetDisplayValue(m_reflectedVar->m_path.c_str()); diff --git a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVarWrapper.h b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVarWrapper.h index 07bb72413a..9c49f1ae1a 100644 --- a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVarWrapper.h +++ b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVarWrapper.h @@ -218,20 +218,6 @@ AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING }; -class EDITOR_CORE_API ReflectedVarAnimationAdapter - : public ReflectedVarAdapter -{ -public: - void SetVariable(IVariable* pVariable) override; - void SyncReflectedVarToIVar(IVariable* pVariable) override; - void SyncIVarToReflectedVar(IVariable* pVariable) override; - CReflectedVar* GetReflectedVar() override { return m_reflectedVar.data(); } -private: -AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING - QScopedPointer m_reflectedVar; -AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING -}; - class EDITOR_CORE_API ReflectedVarResourceAdapter : public ReflectedVarAdapter { diff --git a/Code/Editor/EditorPanelUtils.cpp b/Code/Editor/EditorPanelUtils.cpp index b19bde4583..12e9457474 100644 --- a/Code/Editor/EditorPanelUtils.cpp +++ b/Code/Editor/EditorPanelUtils.cpp @@ -130,7 +130,7 @@ public: HotKey_BuildDefaults(); for (QPair key : keys) { - for (unsigned int j = 0; j < hotkeys.count(); j++) + for (int j = 0; j < hotkeys.count(); j++) { if (hotkeys[j].path.compare(key.first, Qt::CaseInsensitive) == 0) { @@ -256,7 +256,7 @@ public: hotkey.second = settings.value("keySequence").toString(); if (!hotkey.first.isEmpty()) { - for (unsigned int j = 0; j < hotkeys.count(); j++) + for (int j = 0; j < hotkeys.count(); j++) { if (hotkeys[j].path.compare(hotkey.first, Qt::CaseInsensitive) == 0) { diff --git a/Code/Editor/IEditor.h b/Code/Editor/IEditor.h index f66dca412e..7d0fc653fa 100644 --- a/Code/Editor/IEditor.h +++ b/Code/Editor/IEditor.h @@ -68,7 +68,6 @@ class CDisplaySettings; struct SGizmoParameters; class CLevelIndependentFileMan; class CSelectionTreeManager; -struct IResourceSelectorHost; struct SEditorSettings; class CGameExporter; class IAWSResourceManager; @@ -714,7 +713,6 @@ struct IEditor virtual ESystemConfigSpec GetEditorConfigSpec() const = 0; virtual ESystemConfigPlatform GetEditorConfigPlatform() const = 0; virtual void ReloadTemplates() = 0; - virtual IResourceSelectorHost* GetResourceSelectorHost() = 0; virtual void ShowStatusText(bool bEnable) = 0; // Provides a way to extend the context menu of an object. The function gets called every time the menu is opened. diff --git a/Code/Editor/IEditorImpl.cpp b/Code/Editor/IEditorImpl.cpp index 1459139f66..1e268d64ef 100644 --- a/Code/Editor/IEditorImpl.cpp +++ b/Code/Editor/IEditorImpl.cpp @@ -67,7 +67,6 @@ AZ_POP_DISABLE_WARNING #include "EditorFileMonitor.h" #include "MainStatusBar.h" -#include "ResourceSelectorHost.h" #include "Util/FileUtil_impl.h" #include "Util/ImageUtil_impl.h" #include "LogFileImpl.h" @@ -187,7 +186,6 @@ CEditorImpl::CEditorImpl() m_pAnimationContext = new CAnimationContext; m_pImageUtil = new CImageUtil_impl(); - m_pResourceSelectorHost.reset(CreateResourceSelectorHost()); m_selectedRegion.min = Vec3(0, 0, 0); m_selectedRegion.max = Vec3(0, 0, 0); DetectVersion(); diff --git a/Code/Editor/IEditorImpl.h b/Code/Editor/IEditorImpl.h index 02be8bb8e3..2cf6c7805b 100644 --- a/Code/Editor/IEditorImpl.h +++ b/Code/Editor/IEditorImpl.h @@ -290,7 +290,6 @@ public: ESystemConfigPlatform GetEditorConfigPlatform() const; void ReloadTemplates(); void AddErrorMessage(const QString& text, const QString& caption); - IResourceSelectorHost* GetResourceSelectorHost() { return m_pResourceSelectorHost.get(); } virtual void ShowStatusText(bool bEnable); void OnObjectContextMenuOpened(QMenu* pMenu, const CBaseObject* pObject); @@ -374,7 +373,6 @@ protected: //! Export manager for exporting objects and a terrain from the game to DCC tools CExportManager* m_pExportManager; std::unique_ptr m_pEditorFileMonitor; - std::unique_ptr m_pResourceSelectorHost; QString m_selectFileBuffer; QString m_levelNameBuffer; diff --git a/Code/Editor/IEditorPanelUtils.h b/Code/Editor/IEditorPanelUtils.h index 5df15bd86b..4649213ae7 100644 --- a/Code/Editor/IEditorPanelUtils.h +++ b/Code/Editor/IEditorPanelUtils.h @@ -65,7 +65,7 @@ struct HotKey int size = (m_catSize < o_catSize) ? m_catSize : o_catSize; //sort categories to keep them together - for (unsigned int i = 0; i < size; i++) + for (int i = 0; i < size; i++) { if (m_categories[i] < o_categories[i]) { diff --git a/Code/Editor/Include/IResourceSelectorHost.h b/Code/Editor/Include/IResourceSelectorHost.h deleted file mode 100644 index 55ce4e15d3..0000000000 --- a/Code/Editor/Include/IResourceSelectorHost.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - - -#pragma once -// The aim of IResourceSelectorHost is to unify resource selection dialogs in a one -// API that can be reused with plugins. It also makes possible to register new -// resource selectors dynamically, e.g. inside plugins. -// -// Here is how new selectors are created. In your implementation file you add handler function: -// -// #include "IResourceSelectorHost.h" -// -// QString SoundFileSelector(const SResourceSelectorContext& x, const QString& previousValue) -// { -// CMyModalDialog dialog(CWnd::FromHandle(x.parentWindow)); -// ... -// return previousValue; -// } -// REGISTER_RESOURCE_SELECTOR("Sound", SoundFileSelector, "Icons/sound_16x16.png") -// -// Here is how it can be invoked directly: -// -// SResourceSelectorContext x; -// x.parentWindow = parent.GetSafeHwnd(); -// x.typeName = "Sound"; -// string newValue = GetIEditor()->GetResourceSelector()->SelectResource(x, previousValue).c_str(); -// -// If you have your own resource selectors in the plugin you will need to run -// -// RegisterModuleResourceSelectors(GetIEditor()->GetResourceSelector()) -// -// during plugin initialization. -// -// If you want to be able to pass some custom context to the selector (e.g. source of the information for the -// list of items or something similar) then you can add a poitner argument to your selector function, i.e.: -// -// QString SoundFileSelector(const SResourceSelectorContext& x, const QString& previousValue, -// SoundFileList* list) // your context argument - -#include - -class QWidget; - -struct SResourceSelectorContext -{ - const char* typeName; - - // use either parentWidget or parentWindow (not both) until everything porting to QWidget. - QWidget* parentWidget; - - unsigned int entityId; - void* contextObject; - - SResourceSelectorContext() - : parentWidget(0) - , typeName(0) - , entityId(0) - , contextObject() - { - } -}; - -// TResourceSelecitonFunction is used to declare handlers for specific types. -// -// For canceled dialogs previousValue should be returned. -typedef QString (* TResourceSelectionFunction)(const SResourceSelectorContext& selectorContext, const QString& previousValue); -typedef QString (* TResourceSelectionFunctionWithContext)(const SResourceSelectorContext& selectorContext, const QString& previousValue, void* contextObject); - -struct SStaticResourceSelectorEntry; - -// See note at the beginning of the file. -struct IResourceSelectorHost -{ - virtual ~IResourceSelectorHost() = default; - virtual QString SelectResource(const SResourceSelectorContext& context, const QString& previousValue) = 0; - virtual const char* ResourceIconPath(const char* typeName) const = 0; - - virtual void RegisterResourceSelector(const SStaticResourceSelectorEntry* entry) = 0; - - // secondary responsibility of this class is to store global selections - virtual void SetGlobalSelection(const char* resourceType, const char* value) = 0; - virtual const char* GetGlobalSelection(const char* resourceType) const = 0; -}; - -// --------------------------------------------------------------------------- -#define INTERNAL_RSH_COMBINE_UTIL(A, B) A##B -#define INTERNAL_RSH_COMBINE(A, B) INTERNAL_RSH_COMBINE_UTIL(A, B) -#define REGISTER_RESOURCE_SELECTOR(name, function, icon) \ - static SStaticResourceSelectorEntry INTERNAL_RSH_COMBINE(selector_##function, __LINE__)((name), (function), (icon)); - -struct SStaticResourceSelectorEntry -{ - const char* typeName; - TResourceSelectionFunction function; - TResourceSelectionFunctionWithContext functionWithContext; - const char* iconPath; - - static SStaticResourceSelectorEntry*& GetFirst() { static SStaticResourceSelectorEntry* first; return first; } - SStaticResourceSelectorEntry* next; - - SStaticResourceSelectorEntry(const char* typeName, TResourceSelectionFunction function, const char* icon) - : typeName(typeName) - , function(function) - , functionWithContext() - , iconPath(icon) - { - next = GetFirst(); - GetFirst() = this; - } - - template - SStaticResourceSelectorEntry(const char* typeName, QString (*function)(const SResourceSelectorContext&, const QString& previousValue, T * context), const char* icon) - : typeName(typeName) - , function() - , functionWithContext(TResourceSelectionFunctionWithContext(function)) - , iconPath(icon) - { - next = GetFirst(); - GetFirst() = this; - } -}; - -inline void RegisterModuleResourceSelectors(IResourceSelectorHost* editorResourceSelector) -{ - for (SStaticResourceSelectorEntry* current = SStaticResourceSelectorEntry::GetFirst(); current != 0; current = current->next) - { - editorResourceSelector->RegisterResourceSelector(current); - } -} diff --git a/Code/Editor/Lib/Tests/IEditorMock.h b/Code/Editor/Lib/Tests/IEditorMock.h index 9f99b0cd9d..242bf4d25c 100644 --- a/Code/Editor/Lib/Tests/IEditorMock.h +++ b/Code/Editor/Lib/Tests/IEditorMock.h @@ -178,7 +178,6 @@ public: MOCK_CONST_METHOD0(GetEditorConfigSpec, ESystemConfigSpec()); MOCK_CONST_METHOD0(GetEditorConfigPlatform, ESystemConfigPlatform()); MOCK_METHOD0(ReloadTemplates, void()); - MOCK_METHOD0(GetResourceSelectorHost, IResourceSelectorHost* ()); MOCK_METHOD1(ShowStatusText, void(bool )); MOCK_METHOD1(RegisterObjectContextMenuExtension, void(TContextMenuExtensionFunc )); MOCK_METHOD0(GetEnv, SSystemGlobalEnvironment* ()); diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/ComponentEntityEditorPlugin.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/ComponentEntityEditorPlugin.cpp index 3f4cd1b566..50b315b9c3 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/ComponentEntityEditorPlugin.cpp +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/ComponentEntityEditorPlugin.cpp @@ -9,7 +9,6 @@ #include "ComponentEntityEditorPlugin.h" #include -#include "IResourceSelectorHost.h" #include "UI/QComponentEntityEditorMainWindow.h" #include "UI/QComponentEntityEditorOutlinerWindow.h" @@ -180,8 +179,6 @@ ComponentEntityEditorPlugin::ComponentEntityEditorPlugin([[maybe_unused]] IEdito RegisterViewPane(LyViewPane::SliceRelationships, LyViewPane::CategoryTools, options); } - RegisterModuleResourceSelectors(GetIEditor()->GetResourceSelectorHost()); - ComponentEntityEditorPluginInternal::RegisterSandboxObjects(); // Check for common mistakes in component declarations diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp index 66c57361be..b10fe35513 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp @@ -82,7 +82,6 @@ #include #include #include -#include #include "CryEdit.h" #include "Undo/Undo.h" @@ -1387,16 +1386,6 @@ AZStd::string SandboxIntegrationManager::GetLevelName() return AZStd::string(GetIEditor()->GetGameEngine()->GetLevelName().toUtf8().constData()); } -AZStd::string SandboxIntegrationManager::SelectResource(const AZStd::string& resourceType, const AZStd::string& previousValue) -{ - SResourceSelectorContext context; - context.parentWidget = GetMainWindow(); - context.typeName = resourceType.c_str(); - - QString resource = GetEditor()->GetResourceSelectorHost()->SelectResource(context, previousValue.c_str()); - return AZStd::string(resource.toUtf8().constData()); -} - void SandboxIntegrationManager::OnContextReset() { // Deselect everything. diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h index a2ec3b579b..d14ba80bce 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h @@ -158,7 +158,6 @@ private: void LaunchLuaEditor(const char* files) override; bool IsLevelDocumentOpen() override; AZStd::string GetLevelName() override; - AZStd::string SelectResource(const AZStd::string& resourceType, const AZStd::string& previousValue) override; void OpenPinnedInspector(const AzToolsFramework::EntityIdSet& entities) override; void ClosePinnedInspector(AzToolsFramework::EntityPropertyEditor* editor) override; void GoToSelectedOrHighlightedEntitiesInViewports() override; diff --git a/Code/Editor/ResourceSelectorHost.cpp b/Code/Editor/ResourceSelectorHost.cpp deleted file mode 100644 index eb82b57ab4..0000000000 --- a/Code/Editor/ResourceSelectorHost.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - - -#include "EditorDefs.h" - -#include "ResourceSelectorHost.h" - -// Qt -#include -#include - -// AzToolsFramework -#include -#include -#include - - -class CResourceSelectorHost - : public IResourceSelectorHost -{ -public: - CResourceSelectorHost() - { - RegisterModuleResourceSelectors(this); - } - - QString SelectResource(const SResourceSelectorContext& context, const QString& previousValue) override - { - if (!context.typeName) - { - assert(false && "SResourceSelectorContext::typeName is not specified"); - return QString(); - } - - TTypeMap::iterator it = m_typeMap.find(context.typeName); - if (it == m_typeMap.end()) - { - QMessageBox::critical(QApplication::activeWindow(), QString(), QObject::tr("No Resource Selector is registered for resource type \"%1\"").arg(context.typeName)); - return previousValue; - } - - QString result = previousValue; - if (it->second->function) - { - result = it->second->function(context, previousValue); - } - else if (it->second->functionWithContext) - { - result = it->second->functionWithContext(context, previousValue, context.contextObject); - } - - return result; - } - - const char* ResourceIconPath(const char* typeName) const override - { - TTypeMap::const_iterator it = m_typeMap.find(typeName); - if (it != m_typeMap.end()) - { - return it->second->iconPath; - } - return ""; - } - - void RegisterResourceSelector(const SStaticResourceSelectorEntry* entry) override - { - m_typeMap[entry->typeName] = entry; - } - - void SetGlobalSelection(const char* resourceType, const char* value) override - { - if (!resourceType || !value) - { - return; - } - m_globallySelectedResources[resourceType] = value; - } - - const char* GetGlobalSelection(const char* resourceType) const override - { - if (!resourceType) - { - return ""; - } - auto it = m_globallySelectedResources.find(resourceType); - if (it != m_globallySelectedResources.end()) - { - return it->second.c_str(); - } - return ""; - } - -private: - using TTypeMap = std::map>; - TTypeMap m_typeMap; - - std::map m_globallySelectedResources; -}; - -// --------------------------------------------------------------------------- - -IResourceSelectorHost* CreateResourceSelectorHost() -{ - return new CResourceSelectorHost(); -} - -// --------------------------------------------------------------------------- - -QString SoundFileSelector([[maybe_unused]] const SResourceSelectorContext& x, const QString& previousValue) -{ - AssetSelectionModel selection = AssetSelectionModel::AssetTypeSelection("Audio"); - AzToolsFramework::EditorRequests::Bus::Broadcast(&AzToolsFramework::EditorRequests::BrowseForAssets, selection); - if (selection.IsValid()) - { - return Path::FullPathToGamePath(QString(selection.GetResult()->GetFullPath().c_str())); - } - else - { - return Path::FullPathToGamePath(previousValue); - } -} -REGISTER_RESOURCE_SELECTOR("Sound", SoundFileSelector, "") - -// --------------------------------------------------------------------------- -QString ModelFileSelector([[maybe_unused]] const SResourceSelectorContext& x, const QString& previousValue) -{ - AssetSelectionModel selection = AssetSelectionModel::AssetGroupSelection("Geometry"); - AzToolsFramework::EditorRequests::Bus::Broadcast(&AzToolsFramework::EditorRequests::BrowseForAssets, selection); - if (selection.IsValid()) - { - return Path::FullPathToGamePath(QString(selection.GetResult()->GetFullPath().c_str())); - } - else - { - return Path::FullPathToGamePath(previousValue); - } -} -REGISTER_RESOURCE_SELECTOR("Model", ModelFileSelector, "") - -// --------------------------------------------------------------------------- -QString GeomCacheFileSelector([[maybe_unused]] const SResourceSelectorContext& x, const QString& previousValue) -{ - AssetSelectionModel selection = AssetSelectionModel::AssetTypeSelection("Geom Cache"); - AzToolsFramework::EditorRequests::Bus::Broadcast(&AzToolsFramework::EditorRequests::BrowseForAssets, selection); - if (selection.IsValid()) - { - return Path::FullPathToGamePath(QString(selection.GetResult()->GetFullPath().c_str())); - } - else - { - return Path::FullPathToGamePath(previousValue); - } -} - -REGISTER_RESOURCE_SELECTOR("GeomCache", GeomCacheFileSelector, "") - - diff --git a/Code/Editor/ResourceSelectorHost.h b/Code/Editor/ResourceSelectorHost.h deleted file mode 100644 index 266b7c39d1..0000000000 --- a/Code/Editor/ResourceSelectorHost.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - - -#ifndef CRYINCLUDE_EDITOR_RESOURCESELECTORHOST_H -#define CRYINCLUDE_EDITOR_RESOURCESELECTORHOST_H -#pragma once - -#include "IResourceSelectorHost.h" - -IResourceSelectorHost* CreateResourceSelectorHost(); - -#endif // CRYINCLUDE_EDITOR_RESOURCESELECTORHOST_H diff --git a/Code/Editor/Util/Variable.cpp b/Code/Editor/Util/Variable.cpp index ee5ccc9879..97c2a1e8af 100644 --- a/Code/Editor/Util/Variable.cpp +++ b/Code/Editor/Util/Variable.cpp @@ -351,7 +351,7 @@ void CVarBlock::EnableUpdateCallbacks(bool boEnable) void CVarBlock::GatherUsedResourcesInVar(IVariable* pVar, CUsedResources& resources) { int type = pVar->GetDataType(); - if (type == IVariable::DT_FILE || type == IVariable::DT_OBJECT || type == IVariable::DT_TEXTURE) + if (type == IVariable::DT_TEXTURE) { // this is file. QString filename; diff --git a/Code/Editor/Util/Variable.h b/Code/Editor/Util/Variable.h index ecd54e42ae..da506b9db0 100644 --- a/Code/Editor/Util/Variable.h +++ b/Code/Editor/Util/Variable.h @@ -142,15 +142,10 @@ struct IVariable DT_PERCENT, //!< Percent data type, (Same as simple but value is from 0-1 and UI will be from 0-100). DT_COLOR, DT_ANGLE, - DT_FILE, DT_TEXTURE, - DT_ANIMATION, - DT_OBJECT, DT_SHADER, DT_LOCAL_STRING, DT_EQUIP, - DT_REVERBPRESET, - DT_DEPRECATED0, // formerly DT_MATERIAL DT_MATERIALLOOKUP, DT_EXTARRAY, // Extendable Array DT_SEQUENCE, // Movie Sequence (DEPRECATED, use DT_SEQUENCE_ID, instead.) @@ -160,7 +155,6 @@ struct IVariable DT_SEQUENCE_ID, // Movie Sequence DT_LIGHT_ANIMATION, // Light Animation Node in the global Light Animation Set DT_PARTICLE_EFFECT, - DT_GEOM_CACHE, // Geometry cache DT_DEPRECATED, // formerly DT_FLARE DT_AUDIO_TRIGGER, DT_AUDIO_SWITCH, diff --git a/Code/Editor/Util/VariablePropertyType.cpp b/Code/Editor/Util/VariablePropertyType.cpp index 014995467b..17c80a505c 100644 --- a/Code/Editor/Util/VariablePropertyType.cpp +++ b/Code/Editor/Util/VariablePropertyType.cpp @@ -37,17 +37,12 @@ namespace Prop { IVariable::DT_CURVE | IVariable::DT_PERCENT, "FloatCurve", ePropertyFloatCurve, 13 }, { IVariable::DT_CURVE | IVariable::DT_COLOR, "ColorCurve", ePropertyColorCurve, 1 }, { IVariable::DT_ANGLE, "Angle", ePropertyAngle, 0 }, - { IVariable::DT_FILE, "File", ePropertyFile, 7 }, { IVariable::DT_TEXTURE, "Texture", ePropertyTexture, 4 }, - { IVariable::DT_ANIMATION, "Animation", ePropertyAnimation, -1 }, { IVariable::DT_MOTION, "Motion", ePropertyMotion, -1 }, - { IVariable::DT_OBJECT, "Model", ePropertyModel, 5 }, { IVariable::DT_SIMPLE, "Selection", ePropertySelection, -1 }, { IVariable::DT_SIMPLE, "List", ePropertyList, -1 }, { IVariable::DT_SHADER, "Shader", ePropertyShader, 9 }, - { IVariable::DT_DEPRECATED0, "DEPRECATED", ePropertyDeprecated2, -1 }, { IVariable::DT_EQUIP, "Equip", ePropertyEquip, 11 }, - { IVariable::DT_REVERBPRESET, "ReverbPreset", ePropertyReverbPreset, 11 }, { IVariable::DT_LOCAL_STRING, "LocalString", ePropertyLocalString, 3 }, { IVariable::DT_SEQUENCE, "Sequence", ePropertySequence, -1 }, { IVariable::DT_MISSIONOBJ, "Mission Objective", ePropertyMissionObj, -1 }, @@ -55,7 +50,6 @@ namespace Prop { IVariable::DT_SEQUENCE_ID, "SequenceId", ePropertySequenceId, -1 }, { IVariable::DT_LIGHT_ANIMATION, "LightAnimation", ePropertyLightAnimation, -1 }, { IVariable::DT_PARTICLE_EFFECT, "ParticleEffect", ePropertyParticleName, 3 }, - { IVariable::DT_GEOM_CACHE, "Geometry Cache", ePropertyGeomCache, 5 }, { IVariable::DT_AUDIO_TRIGGER, "Audio Trigger", ePropertyAudioTrigger, 6 }, { IVariable::DT_AUDIO_SWITCH, "Audio Switch", ePropertyAudioSwitch, 6 }, { IVariable::DT_AUDIO_SWITCH_STATE, "Audio Switch", ePropertyAudioSwitchState, 6 }, @@ -301,31 +295,4 @@ namespace Prop return -1; } - - const char* GetPropertyTypeToResourceType(PropertyType type) - { - // The strings below are names used together with - // REGISTER_RESOURCE_SELECTOR. See IResourceSelector.h. - switch (type) - { - case ePropertyModel: - return "Model"; - case ePropertyGeomCache: - return "GeomCache"; - case ePropertyAudioTrigger: - return "AudioTrigger"; - case ePropertyAudioSwitch: - return "AudioSwitch"; - case ePropertyAudioSwitchState: - return "AudioSwitchState"; - case ePropertyAudioRTPC: - return "AudioRTPC"; - case ePropertyAudioEnvironment: - return "AudioEnvironment"; - case ePropertyAudioPreloadRequest: - return "AudioPreloadRequest"; - default: - return nullptr; - } - } } diff --git a/Code/Editor/Util/VariablePropertyType.h b/Code/Editor/Util/VariablePropertyType.h index af2865add1..decb930cb3 100644 --- a/Code/Editor/Util/VariablePropertyType.h +++ b/Code/Editor/Util/VariablePropertyType.h @@ -28,16 +28,11 @@ enum PropertyType ePropertyAngle, ePropertyFloatCurve, ePropertyColorCurve, - ePropertyFile, ePropertyTexture, - ePropertyAnimation, - ePropertyModel, ePropertySelection, ePropertyList, ePropertyShader, - ePropertyDeprecated2, // formerly ePropertyMaterial ePropertyEquip, - ePropertyReverbPreset, ePropertyLocalString, ePropertyDeprecated0, // formerly ePropertyCustomAction ePropertyGameToken, @@ -48,7 +43,6 @@ enum PropertyType ePropertyLightAnimation, ePropertyDeprecated1, // formerly ePropertyFlare ePropertyParticleName, - ePropertyGeomCache, ePropertyAudioTrigger, ePropertyAudioSwitch, ePropertyAudioSwitchState, diff --git a/Code/Editor/editor_lib_files.cmake b/Code/Editor/editor_lib_files.cmake index 4b80a5d461..c10db3bac5 100644 --- a/Code/Editor/editor_lib_files.cmake +++ b/Code/Editor/editor_lib_files.cmake @@ -289,7 +289,6 @@ set(FILES Include/IPlugin.h Include/IPreferencesPage.h Include/IRenderListener.h - Include/IResourceSelectorHost.h Include/ISourceControl.h Include/ISubObjectSelectionReferenceFrameCalculator.h Include/ITextureDatabaseUpdater.h @@ -360,8 +359,6 @@ set(FILES Controls/TimelineCtrl.cpp Controls/TimelineCtrl.h Controls/WndGridHelper.h - Controls/ReflectedPropertyControl/PropertyAnimationCtrl.cpp - Controls/ReflectedPropertyControl/PropertyAnimationCtrl.h Controls/ReflectedPropertyControl/PropertyGenericCtrl.cpp Controls/ReflectedPropertyControl/PropertyGenericCtrl.h Controls/ReflectedPropertyControl/PropertyMiscCtrl.cpp @@ -372,8 +369,6 @@ set(FILES Controls/ReflectedPropertyControl/PropertyResourceCtrl.h Controls/ReflectedPropertyControl/PropertyCtrl.cpp Controls/ReflectedPropertyControl/PropertyCtrl.h - Controls/ReflectedPropertyControl/ReflectedPropertiesPanel.cpp - Controls/ReflectedPropertyControl/ReflectedPropertiesPanel.h MainStatusBar.cpp MainStatusBar.h MainStatusBarItems.h @@ -590,8 +585,6 @@ set(FILES FBXExporterDialog.ui FileTypeUtils.cpp LightmapCompiler/SimpleTriangleRasterizer.cpp - ResourceSelectorHost.cpp - ResourceSelectorHost.h ToolBox.cpp TrackViewNewSequenceDialog.cpp TrackViewNewSequenceDialog.ui @@ -668,7 +661,6 @@ set(FILES TrackView/2DBezierKeyUIControls.cpp TrackView/AssetBlendKeyUIControls.cpp TrackView/CaptureKeyUIControls.cpp - TrackView/CharacterKeyUIControls.cpp TrackView/ConsoleKeyUIControls.cpp TrackView/EventKeyUIControls.cpp TrackView/GotoKeyUIControls.cpp diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h index f6046b9f25..9e5db5b5b7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h @@ -841,9 +841,6 @@ namespace AzToolsFramework */ virtual AZStd::string GetComponentIconPath(const AZ::Uuid& /*componentType*/, AZ::Crc32 /*componentIconAttrib*/, AZ::Component* /*component*/) { return AZStd::string(); } - /// Resource Selector hook, returns a path for a resource. - virtual AZStd::string SelectResource(const AZStd::string& /*resourceType*/, const AZStd::string& /*previousValue*/) { return AZStd::string(); } - /** * Calculate the navigation 2D radius in units of an agent given its Navigation Type Name * @param angentTypeName the name that identifies the agent navigation type diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAudioCtrl.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAudioCtrl.cpp index 6951d7ae8c..274db35da2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAudioCtrl.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAudioCtrl.cpp @@ -7,8 +7,8 @@ */ -#include "PropertyAudioCtrl.h" -#include "PropertyQTConstants.h" +#include +#include #include #include @@ -34,7 +34,7 @@ namespace AzToolsFramework : QWidget(parent) , m_browseEdit(nullptr) , m_mainLayout(nullptr) - , m_propertyType(AudioPropertyType::Invalid) + , m_propertyType(AudioPropertyType::NumTypes) { // create the gui m_mainLayout = new QHBoxLayout(); @@ -96,7 +96,7 @@ namespace AzToolsFramework return; } - if (type != AudioPropertyType::Invalid) + if (type != AudioPropertyType::NumTypes) { m_propertyType = type; } @@ -136,10 +136,11 @@ namespace AzToolsFramework void AudioControlSelectorWidget::OnOpenAudioControlSelector() { - AZStd::string resourceResult; - AZStd::string resourceType(GetResourceSelectorNameFromType(m_propertyType)); AZStd::string currentValue(m_controlName.toStdString().c_str()); - EditorRequests::Bus::BroadcastResult(resourceResult, &EditorRequests::Bus::Events::SelectResource, resourceType, currentValue); + AZStd::string resourceResult; + AudioControlSelectorRequestBus::EventResult( + resourceResult, m_propertyType, + &AudioControlSelectorRequestBus::Events::SelectResource, currentValue); SetControlName(QString(resourceResult.c_str())); } @@ -167,12 +168,12 @@ namespace AzToolsFramework { case AudioPropertyType::Trigger: return { "AudioTrigger" }; + case AudioPropertyType::Rtpc: + return { "AudioRTPC" }; case AudioPropertyType::Switch: return { "AudioSwitch" }; case AudioPropertyType::SwitchState: return { "AudioSwitchState" }; - case AudioPropertyType::Rtpc: - return { "AudioRTPC" }; case AudioPropertyType::Environment: return { "AudioEnvironment" }; case AudioPropertyType::Preload: diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAudioCtrl.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAudioCtrl.h index 4996806a8d..dbc45a592d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAudioCtrl.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAudioCtrl.h @@ -29,6 +29,27 @@ class QMimeData; namespace AzToolsFramework { + //============================================================================= + // Audio Control Selector Request Bus + // For connecting UI proper + //============================================================================= + class AudioControlSelectorRequests + : public AZ::EBusTraits + { + public: + // EBusTraits + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; + using BusIdType = AudioPropertyType; + + virtual AZStd::string SelectResource(AZStd::string_view previousValue) + { + return previousValue; + } + }; + + using AudioControlSelectorRequestBus = AZ::EBus; + //============================================================================= // Audio Control Selector Widget //============================================================================= diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAudioCtrlTypes.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAudioCtrlTypes.h index df31e297cd..c23e082a44 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAudioCtrlTypes.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAudioCtrlTypes.h @@ -18,15 +18,15 @@ namespace AzToolsFramework { //========================================================================= - enum class AudioPropertyType + enum class AudioPropertyType : AZ::u32 { - Invalid = 0, - Trigger, + Trigger = 0, + Rtpc, Switch, SwitchState, - Rtpc, Environment, Preload, + NumTypes, }; //========================================================================= @@ -40,7 +40,7 @@ namespace AzToolsFramework virtual ~CReflectedVarAudioControl() = default; AZStd::string m_controlName; - AudioPropertyType m_propertyType = AudioPropertyType::Invalid; + AudioPropertyType m_propertyType = AudioPropertyType::NumTypes; static void Reflect(AZ::ReflectContext* context) { diff --git a/Gems/AudioSystem/Code/Source/Editor/ATLControlsResourceDialog.cpp b/Gems/AudioSystem/Code/Source/Editor/ATLControlsResourceDialog.cpp index 46941baf17..d3121f6245 100644 --- a/Gems/AudioSystem/Code/Source/Editor/ATLControlsResourceDialog.cpp +++ b/Gems/AudioSystem/Code/Source/Editor/ATLControlsResourceDialog.cpp @@ -30,6 +30,8 @@ namespace AudioControls : QDialog(pParent) , m_eType(eType) { + AZ_Assert(CAudioControlsEditorPlugin::GetATLModel() != nullptr, "ATLControlsDialog - ATL Model is null!"); + setWindowTitle(GetWindowTitle(m_eType)); setWindowModality(Qt::ApplicationModal); diff --git a/Gems/AudioSystem/Code/Source/Editor/AudioControlsEditorPlugin.cpp b/Gems/AudioSystem/Code/Source/Editor/AudioControlsEditorPlugin.cpp index 2b7023df61..f3d5a03ffc 100644 --- a/Gems/AudioSystem/Code/Source/Editor/AudioControlsEditorPlugin.cpp +++ b/Gems/AudioSystem/Code/Source/Editor/AudioControlsEditorPlugin.cpp @@ -14,8 +14,6 @@ #include #include -#include - #include #include #include @@ -41,7 +39,6 @@ CAudioControlsEditorPlugin::CAudioControlsEditorPlugin(IEditor* editor) QtViewOptions options; options.canHaveMultipleInstances = true; RegisterQtViewPane(editor, LyViewPane::AudioControlsEditor, LyViewPane::CategoryOther, options); - RegisterAudioControlsResourceSelectors(); Audio::AudioSystemRequestBus::BroadcastResult(ms_pIAudioProxy, &Audio::AudioSystemRequestBus::Events::GetFreeAudioProxy); diff --git a/Gems/AudioSystem/Code/Source/Editor/AudioControlsEditorPlugin.h b/Gems/AudioSystem/Code/Source/Editor/AudioControlsEditorPlugin.h index 4e5c528901..f8288a5d7f 100644 --- a/Gems/AudioSystem/Code/Source/Editor/AudioControlsEditorPlugin.h +++ b/Gems/AudioSystem/Code/Source/Editor/AudioControlsEditorPlugin.h @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -68,6 +69,7 @@ private: static AudioControls::FilepathSet ms_currentFilenames; static Audio::IAudioProxy* ms_pIAudioProxy; static Audio::TAudioControlID ms_nAudioTriggerID; - static CImplementationManager ms_implementationManager; + + AudioControls::AudioControlSelectorHandler m_controlSelector; }; diff --git a/Gems/AudioSystem/Code/Source/Editor/AudioResourceSelectors.cpp b/Gems/AudioSystem/Code/Source/Editor/AudioResourceSelectors.cpp index 74233be2e9..a6ab3878b8 100644 --- a/Gems/AudioSystem/Code/Source/Editor/AudioResourceSelectors.cpp +++ b/Gems/AudioSystem/Code/Source/Editor/AudioResourceSelectors.cpp @@ -10,88 +10,45 @@ #include #include #include -#include -#include #include +#include + namespace AudioControls { //-------------------------------------------------------------------------------------------// - QString ShowSelectDialog(const SResourceSelectorContext& context, const QString& pPreviousValue, const EACEControlType controlType) + AudioControlSelectorHandler::AudioControlSelectorHandler() { - AZ_Assert(CAudioControlsEditorPlugin::GetATLModel() != nullptr, "AudioResourceSelectors - ATL Model is null!"); - - AZStd::string levelName; - AzToolsFramework::EditorRequestBus::BroadcastResult(levelName, &AzToolsFramework::EditorRequests::GetLevelName); - - ATLControlsDialog dialog(context.parentWidget, controlType); - dialog.SetScope(levelName); - return dialog.ChooseItem(pPreviousValue.toUtf8().constData()); - } - - //-------------------------------------------------------------------------------------------// - QString AudioTriggerSelector(const SResourceSelectorContext& context, const QString& pPreviousValue) - { - return ShowSelectDialog(context, pPreviousValue, eACET_TRIGGER); - } - - //-------------------------------------------------------------------------------------------// - QString AudioSwitchSelector(const SResourceSelectorContext& context, const QString& pPreviousValue) - { - return ShowSelectDialog(context, pPreviousValue, eACET_SWITCH); - } - - //-------------------------------------------------------------------------------------------// - QString AudioSwitchStateSelector(const SResourceSelectorContext& context, const QString& pPreviousValue) - { - return ShowSelectDialog(context, pPreviousValue, eACET_SWITCH_STATE); - } - - //-------------------------------------------------------------------------------------------// - QString AudioRTPCSelector(const SResourceSelectorContext& context, const QString& pPreviousValue) - { - return ShowSelectDialog(context, pPreviousValue, eACET_RTPC); - } - - //-------------------------------------------------------------------------------------------// - QString AudioEnvironmentSelector(const SResourceSelectorContext& context, const QString& pPreviousValue) - { - return ShowSelectDialog(context, pPreviousValue, eACET_ENVIRONMENT); - } - - //-------------------------------------------------------------------------------------------// - QString AudioPreloadRequestSelector(const SResourceSelectorContext& context, const QString& pPreviousValue) - { - return ShowSelectDialog(context, pPreviousValue, eACET_PRELOAD); - } - - //-------------------------------------------------------------------------------------------// - static SStaticResourceSelectorEntry audioTriggerSelector( - "AudioTrigger", AudioTriggerSelector, ":/Icons/Trigger_Icon.svg"); - static SStaticResourceSelectorEntry audioSwitchSelector( - "AudioSwitch", AudioSwitchSelector, ":/Icons/Switch_Icon.svg"); - static SStaticResourceSelectorEntry audioStateSelector( - "AudioSwitchState", AudioSwitchStateSelector, ":/Icons/Property_Icon.png"); - static SStaticResourceSelectorEntry audioRtpcSelector( - "AudioRTPC", AudioRTPCSelector, ":/Icons/RTPC_Icon.svg"); - static SStaticResourceSelectorEntry audioEnvironmentSelector( - "AudioEnvironment", AudioEnvironmentSelector, ":/Icons/Environment_Icon.svg"); - static SStaticResourceSelectorEntry audioPreloadSelector( - "AudioPreloadRequest", AudioPreloadRequestSelector, ":/Icons/Bank_Icon.png"); - - //-------------------------------------------------------------------------------------------// - void RegisterAudioControlsResourceSelectors() - { - if (IResourceSelectorHost* host = GetIEditor()->GetResourceSelectorHost(); - host != nullptr) + for (AZ::u32 type = 0; type < static_cast(AzToolsFramework::AudioPropertyType::NumTypes); ++type) { - host->RegisterResourceSelector(&audioTriggerSelector); - host->RegisterResourceSelector(&audioSwitchSelector); - host->RegisterResourceSelector(&audioStateSelector); - host->RegisterResourceSelector(&audioRtpcSelector); - host->RegisterResourceSelector(&audioEnvironmentSelector); - host->RegisterResourceSelector(&audioPreloadSelector); + AzToolsFramework::AudioControlSelectorRequestBus::MultiHandler::BusConnect( + static_cast(type)); } } + AudioControlSelectorHandler::~AudioControlSelectorHandler() + { + AzToolsFramework::AudioControlSelectorRequestBus::MultiHandler::BusDisconnect(); + } + + AZStd::string AudioControlSelectorHandler::SelectResource(AZStd::string_view previousValue) + { + using namespace AzToolsFramework; + if (auto busId = AudioControlSelectorRequestBus::GetCurrentBusId(); + busId != nullptr) + { + auto controlType = static_cast(*busId); + QWidget* parentWidget = nullptr; + AzToolsFramework::EditorRequestBus::BroadcastResult(parentWidget, &AzToolsFramework::EditorRequestBus::Events::GetMainWindow); + + AZStd::string levelName; + AzToolsFramework::EditorRequestBus::BroadcastResult(levelName, &AzToolsFramework::EditorRequests::GetLevelName); + + ATLControlsDialog dialog(parentWidget, controlType); + dialog.SetScope(levelName); + return dialog.ChooseItem(previousValue.data()); + } + return previousValue; + } + } // namespace AudioControls diff --git a/Gems/AudioSystem/Code/Source/Editor/AudioResourceSelectors.h b/Gems/AudioSystem/Code/Source/Editor/AudioResourceSelectors.h index d2bff7c799..127cfb15b4 100644 --- a/Gems/AudioSystem/Code/Source/Editor/AudioResourceSelectors.h +++ b/Gems/AudioSystem/Code/Source/Editor/AudioResourceSelectors.h @@ -8,7 +8,16 @@ #pragma once +#include + namespace AudioControls { - void RegisterAudioControlsResourceSelectors(); + class AudioControlSelectorHandler + : public AzToolsFramework::AudioControlSelectorRequestBus::MultiHandler + { + public: + AudioControlSelectorHandler(); + ~AudioControlSelectorHandler(); + AZStd::string SelectResource(AZStd::string_view previousValue) override; + }; } From 88bef1074bc20ac4e8dd543af1bc7f345bddfd5f Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Mon, 16 Aug 2021 15:43:01 -0500 Subject: [PATCH 69/70] Replaced some Lumberyard references with O3DE. Signed-off-by: Chris Galvan --- .../Gem/PythonTests/EditorPythonTestTools/README.txt | 4 ++-- .../PythonTests/editor/EditorScripts/AssetPicker_UI_UX.py | 2 +- .../BasicEditorWorkflows_LevelEntityComponentCRUD.py | 4 ++-- .../editor/EditorScripts/Menus_EditMenuOptions.py | 2 +- .../editor/EditorScripts/Menus_FileMenuOptions.py | 2 +- .../editor/EditorScripts/Menus_ViewMenuOptions.py | 2 +- .../scripting/Pane_PropertiesChanged_RetainsOnRestart.py | 2 +- .../Gem/PythonTests/smoke/Editor_NewExistingLevels_Works.py | 2 +- Gems/QtForPython/Editor/Scripts/tests/log_main_window.py | 2 +- .../Include/ScriptCanvas/Libraries/Entity/EntityNodes.h | 6 +++--- .../Include/ScriptCanvas/Libraries/Math/TransformNodes.h | 6 +++--- 11 files changed, 17 insertions(+), 17 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/README.txt b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/README.txt index 0405dacbf4..90afee39bc 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/README.txt +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/README.txt @@ -8,7 +8,7 @@ INTRODUCTION ------------ EditorPythonBindings is a Python project that contains a collection of editor testing tools -developed by the Lumberyard feature teams. The project contains tools for system level +developed by the O3DE feature teams. The project contains tools for system level editor tests. @@ -23,7 +23,7 @@ installed on your system. INSTALL ----------- -It is recommended to set up these these tools with Lumberyard's CMake build commands. +It is recommended to set up these these tools with O3DE's CMake build commands. Assuming CMake is already setup on your operating system, below are some sample build commands: cd /path/to/od3e/ mkdir windows_vs2019 diff --git a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/AssetPicker_UI_UX.py b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/AssetPicker_UI_UX.py index f728714125..068f25fb1e 100644 --- a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/AssetPicker_UI_UX.py +++ b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/AssetPicker_UI_UX.py @@ -61,7 +61,7 @@ class AssetPickerUIUXTest(EditorTestHelper): 5) Verify if Mesh Asset is assigned via both OK/Enter options Note: - - This test file must be called from the Lumberyard Editor command terminal + - This test file must be called from the O3DE Editor command terminal - Any passed and failed tests are written to the Editor.log file. Parsing the file or running a log_monitor are required to observe the test results. diff --git a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/BasicEditorWorkflows_LevelEntityComponentCRUD.py b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/BasicEditorWorkflows_LevelEntityComponentCRUD.py index 32d20ea2b4..994fc661ed 100644 --- a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/BasicEditorWorkflows_LevelEntityComponentCRUD.py +++ b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/BasicEditorWorkflows_LevelEntityComponentCRUD.py @@ -37,7 +37,7 @@ class TestBasicEditorWorkflows(EditorTestHelper): async def run_test(self): """ Summary: - Open Lumberyard editor and check if basic Editor workflows are completable. + Open O3DE editor and check if basic Editor workflows are completable. Expected Behavior: - A new level can be created @@ -48,7 +48,7 @@ class TestBasicEditorWorkflows(EditorTestHelper): - Level can be exported Note: - - This test file must be called from the Lumberyard Editor command terminal + - This test file must be called from the O3DE Editor command terminal - Any passed and failed tests are written to the Editor.log file. Parsing the file or running a log_monitor are required to observe the test results. diff --git a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_EditMenuOptions.py b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_EditMenuOptions.py index 6b861894c0..53a8da4116 100644 --- a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_EditMenuOptions.py +++ b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_EditMenuOptions.py @@ -36,7 +36,7 @@ class TestEditMenuOptions(EditorTestHelper): 2) Interact with Edit Menu options Note: - - This test file must be called from the Lumberyard Editor command terminal + - This test file must be called from the O3DE Editor command terminal - Any passed and failed tests are written to the Editor.log file. Parsing the file or running a log_monitor are required to observe the test results. diff --git a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_FileMenuOptions.py b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_FileMenuOptions.py index ab9aa1d326..77ee9ac61d 100644 --- a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_FileMenuOptions.py +++ b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_FileMenuOptions.py @@ -32,7 +32,7 @@ class TestFileMenuOptions(EditorTestHelper): 2) Interact with File Menu options Note: - - This test file must be called from the Lumberyard Editor command terminal + - This test file must be called from the O3DE Editor command terminal - Any passed and failed tests are written to the Editor.log file. Parsing the file or running a log_monitor are required to observe the test results. diff --git a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_ViewMenuOptions.py b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_ViewMenuOptions.py index d1233e9815..d2db4210ce 100644 --- a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_ViewMenuOptions.py +++ b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_ViewMenuOptions.py @@ -36,7 +36,7 @@ class TestViewMenuOptions(EditorTestHelper): 2) Interact with View Menu options Note: - - This test file must be called from the Lumberyard Editor command terminal + - This test file must be called from the O3DE Editor command terminal - Any passed and failed tests are written to the Editor.log file. Parsing the file or running a log_monitor are required to observe the test results. diff --git a/AutomatedTesting/Gem/PythonTests/scripting/Pane_PropertiesChanged_RetainsOnRestart.py b/AutomatedTesting/Gem/PythonTests/scripting/Pane_PropertiesChanged_RetainsOnRestart.py index 5c74754449..338389b1c4 100644 --- a/AutomatedTesting/Gem/PythonTests/scripting/Pane_PropertiesChanged_RetainsOnRestart.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/Pane_PropertiesChanged_RetainsOnRestart.py @@ -52,7 +52,7 @@ def Pane_PropertiesChanged_RetainsOnRestart(): from utils import TestHelper as helper import pyside_utils - # Lumberyard Imports + # O3DE Imports import azlmbr.legacy.general as general # Pyside imports diff --git a/AutomatedTesting/Gem/PythonTests/smoke/Editor_NewExistingLevels_Works.py b/AutomatedTesting/Gem/PythonTests/smoke/Editor_NewExistingLevels_Works.py index 9a54de856c..71956488fc 100644 --- a/AutomatedTesting/Gem/PythonTests/smoke/Editor_NewExistingLevels_Works.py +++ b/AutomatedTesting/Gem/PythonTests/smoke/Editor_NewExistingLevels_Works.py @@ -53,7 +53,7 @@ def Editor_NewExistingLevels_Works(): 10) Save, Load and Export an existing level and close editor Note: - - This test file must be called from the Lumberyard Editor command terminal + - This test file must be called from the O3DE Editor command terminal - Any passed and failed tests are written to the Editor.log file. Parsing the file or running a log_monitor are required to observe the test results. diff --git a/Gems/QtForPython/Editor/Scripts/tests/log_main_window.py b/Gems/QtForPython/Editor/Scripts/tests/log_main_window.py index 528e869d8c..6971731cb0 100755 --- a/Gems/QtForPython/Editor/Scripts/tests/log_main_window.py +++ b/Gems/QtForPython/Editor/Scripts/tests/log_main_window.py @@ -5,7 +5,7 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -# bit more complex example set to demo connecting Lumberyard tech to PySide2 widgets +# bit more complex example set to demo connecting O3DE tech to PySide2 widgets import azlmbr.bus from PySide2 import QtWidgets from PySide2 import QtGui diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Entity/EntityNodes.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Entity/EntityNodes.h index 701c3a0869..191635757c 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Entity/EntityNodes.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Entity/EntityNodes.h @@ -35,7 +35,7 @@ namespace ScriptCanvas vector.SetLength(aznumeric_cast(scale)); return vector; } - SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(GetEntityRight, DefaultScale<1>, k_categoryName, "{C12282BE-29D2-497D-8C22-75B940E254E2}", "returns the right direction vector from the specified entity's world transform, scaled by a given value (Lumberyard uses Z up, right handed)", "EntityId", "Scale"); + SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(GetEntityRight, DefaultScale<1>, k_categoryName, "{C12282BE-29D2-497D-8C22-75B940E254E2}", "returns the right direction vector from the specified entity's world transform, scaled by a given value (O3DE uses Z up, right handed)", "EntityId", "Scale"); AZ_INLINE Vector3Type GetEntityForward(AZ::EntityId entityId, NumberType scale) { @@ -46,7 +46,7 @@ namespace ScriptCanvas vector.SetLength(aznumeric_cast(scale)); return vector; } - SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(GetEntityForward, DefaultScale<1>, k_categoryName, "{719D9F76-84D4-4B0F-BCEB-26D5D097C7D6}", "returns the forward direction vector from the specified entity' world transform, scaled by a given value (Lumberyard uses Z up, right handed)", "EntityId", "Scale"); + SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(GetEntityForward, DefaultScale<1>, k_categoryName, "{719D9F76-84D4-4B0F-BCEB-26D5D097C7D6}", "returns the forward direction vector from the specified entity' world transform, scaled by a given value (O3DE uses Z up, right handed)", "EntityId", "Scale"); AZ_INLINE Vector3Type GetEntityUp(AZ::EntityId entityId, NumberType scale) { @@ -57,7 +57,7 @@ namespace ScriptCanvas vector.SetLength(aznumeric_cast(scale)); return vector; } - SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(GetEntityUp, DefaultScale<1>, k_categoryName, "{96B86F3F-F022-4611-9AEA-175EA952C562}", "returns the up direction vector from the specified entity's world transform, scaled by a given value (Lumberyard uses Z up, right handed)", "EntityId", "Scale"); + SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(GetEntityUp, DefaultScale<1>, k_categoryName, "{96B86F3F-F022-4611-9AEA-175EA952C562}", "returns the up direction vector from the specified entity's world transform, scaled by a given value (O3DE uses Z up, right handed)", "EntityId", "Scale"); AZ_INLINE BooleanType IsActive(const EntityIDType& entityId) { diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/TransformNodes.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/TransformNodes.h index ddbe5ac5f7..f2088dbf6d 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/TransformNodes.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Math/TransformNodes.h @@ -74,7 +74,7 @@ namespace ScriptCanvas vector.SetLength(aznumeric_cast(scale)); return vector; } - SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(GetRight, DefaultScale<1>, k_categoryName, "{65811752-711F-4566-869E-5AEF53206342}", "returns the right direction vector from the specified transform scaled by a given value (Lumberyard uses Z up, right handed)", "Source", "Scale"); + SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(GetRight, DefaultScale<1>, k_categoryName, "{65811752-711F-4566-869E-5AEF53206342}", "returns the right direction vector from the specified transform scaled by a given value (O3DE uses Z up, right handed)", "Source", "Scale"); AZ_INLINE Vector3Type GetForward(const TransformType& source, NumberType scale) { @@ -82,7 +82,7 @@ namespace ScriptCanvas vector.SetLength(aznumeric_cast(scale)); return vector; } - SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(GetForward, DefaultScale<1>, k_categoryName, "{3602a047-9f12-46d4-9648-8f53770c8130}", "returns the forward direction vector from the specified transform scaled by a given value (Lumberyard uses Z up, right handed)", "Source", "Scale"); + SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(GetForward, DefaultScale<1>, k_categoryName, "{3602a047-9f12-46d4-9648-8f53770c8130}", "returns the forward direction vector from the specified transform scaled by a given value (O3DE uses Z up, right handed)", "Source", "Scale"); AZ_INLINE Vector3Type GetUp(const TransformType& source, NumberType scale) { @@ -90,7 +90,7 @@ namespace ScriptCanvas vector.SetLength(aznumeric_cast(scale)); return vector; } - SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(GetUp, DefaultScale<1>, k_categoryName, "{F10F52D2-E6F2-4E39-84D5-B4A561F186D3}", "returns the up direction vector from the specified transform scaled by a given value (Lumberyard uses Z up, right handed)", "Source", "Scale"); + SCRIPT_CANVAS_GENERIC_FUNCTION_NODE_WITH_DEFAULTS(GetUp, DefaultScale<1>, k_categoryName, "{F10F52D2-E6F2-4E39-84D5-B4A561F186D3}", "returns the up direction vector from the specified transform scaled by a given value (O3DE uses Z up, right handed)", "Source", "Scale"); AZ_INLINE Vector3Type GetTranslation(const TransformType& source) { From a461a82030e5aa7f77e0a8337b61d7f8abfc3885 Mon Sep 17 00:00:00 2001 From: mgwynn Date: Mon, 16 Aug 2021 18:13:35 -0400 Subject: [PATCH 70/70] Remove non-existant files from icon contents.json files (#3148) Signed-off-by: mgwynn --- .../AppIcon.appiconset/Contents.json | 32 +------------ .../Contents.json | 32 +------------ .../LaunchImage.launchimage/Contents.json | 47 +------------------ 3 files changed, 3 insertions(+), 108 deletions(-) diff --git a/AutomatedTesting/Gem/Resources/IOSLauncher/Images.xcassets/AppIcon.appiconset/Contents.json b/AutomatedTesting/Gem/Resources/IOSLauncher/Images.xcassets/AppIcon.appiconset/Contents.json index 09621469c3..94e3dcd84d 100644 --- a/AutomatedTesting/Gem/Resources/IOSLauncher/Images.xcassets/AppIcon.appiconset/Contents.json +++ b/AutomatedTesting/Gem/Resources/IOSLauncher/Images.xcassets/AppIcon.appiconset/Contents.json @@ -1,17 +1,5 @@ { "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "iPhoneNotificationIcon40x40.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "iPhoneNotificationIcon60x60.png", - "scale" : "3x" - }, { "size" : "29x29", "idiom" : "iphone", @@ -48,18 +36,6 @@ "filename" : "iPhoneAppIcon180x180.png", "scale" : "3x" }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "iPadNotificationIcon20x20.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "iPadNotificationIcon40x40.png", - "scale" : "2x" - }, { "size" : "29x29", "idiom" : "ipad", @@ -101,16 +77,10 @@ "idiom" : "ipad", "filename" : "iPadProAppIcon167x167.png", "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "iOSAppStoreIcon1024x1024.png", - "scale" : "1x" } ], "info" : { "version" : 1, "author" : "xcode" } -} \ No newline at end of file +} diff --git a/AutomatedTesting/Gem/Resources/IOSLauncher/Images.xcassets/AutomatedTestingAppIcon.appiconset/Contents.json b/AutomatedTesting/Gem/Resources/IOSLauncher/Images.xcassets/AutomatedTestingAppIcon.appiconset/Contents.json index 09621469c3..94e3dcd84d 100644 --- a/AutomatedTesting/Gem/Resources/IOSLauncher/Images.xcassets/AutomatedTestingAppIcon.appiconset/Contents.json +++ b/AutomatedTesting/Gem/Resources/IOSLauncher/Images.xcassets/AutomatedTestingAppIcon.appiconset/Contents.json @@ -1,17 +1,5 @@ { "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "iPhoneNotificationIcon40x40.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "iPhoneNotificationIcon60x60.png", - "scale" : "3x" - }, { "size" : "29x29", "idiom" : "iphone", @@ -48,18 +36,6 @@ "filename" : "iPhoneAppIcon180x180.png", "scale" : "3x" }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "iPadNotificationIcon20x20.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "iPadNotificationIcon40x40.png", - "scale" : "2x" - }, { "size" : "29x29", "idiom" : "ipad", @@ -101,16 +77,10 @@ "idiom" : "ipad", "filename" : "iPadProAppIcon167x167.png", "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "iOSAppStoreIcon1024x1024.png", - "scale" : "1x" } ], "info" : { "version" : 1, "author" : "xcode" } -} \ No newline at end of file +} diff --git a/AutomatedTesting/Gem/Resources/IOSLauncher/Images.xcassets/LaunchImage.launchimage/Contents.json b/AutomatedTesting/Gem/Resources/IOSLauncher/Images.xcassets/LaunchImage.launchimage/Contents.json index f836f07ee7..67b253d091 100644 --- a/AutomatedTesting/Gem/Resources/IOSLauncher/Images.xcassets/LaunchImage.launchimage/Contents.json +++ b/AutomatedTesting/Gem/Resources/IOSLauncher/Images.xcassets/LaunchImage.launchimage/Contents.json @@ -1,50 +1,5 @@ { "images" : [ - { - "extent" : "full-screen", - "idiom" : "iphone", - "subtype" : "2436h", - "filename" : "iPhoneLaunchImage1125x2436.png", - "minimum-system-version" : "11.0", - "orientation" : "portrait", - "scale" : "3x" - }, - { - "extent" : "full-screen", - "idiom" : "iphone", - "subtype" : "2436h", - "filename" : "iPhoneLaunchImage2436x1125.png", - "minimum-system-version" : "11.0", - "orientation" : "landscape", - "scale" : "3x" - }, - { - "extent" : "full-screen", - "idiom" : "iphone", - "subtype" : "736h", - "filename" : "iPhoneLaunchImage1242x2208.png", - "minimum-system-version" : "8.0", - "orientation" : "portrait", - "scale" : "3x" - }, - { - "extent" : "full-screen", - "idiom" : "iphone", - "subtype" : "736h", - "filename" : "iPhoneLaunchImage2208x1242.png", - "minimum-system-version" : "8.0", - "orientation" : "landscape", - "scale" : "3x" - }, - { - "extent" : "full-screen", - "idiom" : "iphone", - "subtype" : "667h", - "filename" : "iPhoneLaunchImage750x1334.png", - "minimum-system-version" : "8.0", - "orientation" : "portrait", - "scale" : "2x" - }, { "orientation" : "portrait", "idiom" : "iphone", @@ -166,4 +121,4 @@ "version" : 1, "author" : "xcode" } -} \ No newline at end of file +}