From 4b610058b5eadc9f2885885094eb2858cebb8db5 Mon Sep 17 00:00:00 2001 From: chiyteng Date: Wed, 26 May 2021 15:47:41 -0700 Subject: [PATCH 01/14] implement function DetachPrefabFromParent in PrefabPublicHandler --- .../Prefab/Instance/Instance.cpp | 12 + .../Prefab/Instance/Instance.h | 5 +- .../Instance/InstanceToTemplatePropagator.cpp | 5 + .../Prefab/PrefabPublicHandler.cpp | 224 +++++++++++++++++- .../Prefab/PrefabPublicHandler.h | 2 + .../Prefab/PrefabPublicInterface.h | 8 + .../UI/Prefab/PrefabIntegrationManager.cpp | 32 +++ .../UI/Prefab/PrefabIntegrationManager.h | 1 + 8 files changed, 275 insertions(+), 14 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp index c4cb3e0316..8c7604f680 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp @@ -401,6 +401,17 @@ namespace AzToolsFramework } } + InstancePtrOptionalReference Instance::GetNestedInstance(const InstanceAlias& instanceAlias) + { + auto nestedInstanceIterator = m_nestedInstances.find(instanceAlias); + if (nestedInstanceIterator != m_nestedInstances.end()) + { + return nestedInstanceIterator->second; + } + + return AZStd::nullopt; + } + void Instance::GetNestedInstances(const AZStd::function&)>& callback) { for (auto& [instanceAlias, instance] : m_nestedInstances) @@ -613,6 +624,7 @@ namespace AzToolsFramework AZStd::unique_ptr Instance::DetachContainerEntity() { + m_instanceEntityMapper->UnregisterEntity(m_containerEntity->GetId()); return AZStd::move(m_containerEntity); } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h index 821478b706..377be68753 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h @@ -48,6 +48,8 @@ namespace AzToolsFramework using EntityAliasOptionalReference = AZStd::optional>; using InstanceOptionalReference = AZStd::optional>; using InstanceOptionalConstReference = AZStd::optional>; + using InstancePtrOptionalReference = AZStd::optional>>; + using InstanceSet = AZStd::unordered_set; using InstanceSetConstReference = AZStd::optional>; using EntityOptionalReference = AZStd::optional>; @@ -85,6 +87,7 @@ namespace AzToolsFramework bool AddEntity(AZ::Entity& entity); bool AddEntity(AZ::Entity& entity, EntityAlias entityAlias); AZStd::unique_ptr DetachEntity(const AZ::EntityId& entityId); + void DetachEntities(const AZStd::function)>& callback); void DetachNestedEntities(const AZStd::function)>& callback); void RemoveNestedEntities(const AZStd::function&)>& filter); @@ -92,6 +95,7 @@ namespace AzToolsFramework Instance& AddInstance(AZStd::unique_ptr instance); AZStd::unique_ptr DetachNestedInstance(const InstanceAlias& instanceAlias); + InstancePtrOptionalReference GetNestedInstance(const InstanceAlias& instanceAlias); /** * Gets the aliases for the entities in the Instance DOM. @@ -182,7 +186,6 @@ namespace AzToolsFramework void ClearEntities(); - void DetachEntities(const AZStd::function)>& callback); void RemoveEntities(const AZStd::function&)>& filter); bool RegisterEntity(const AZ::EntityId& entityId, const EntityAlias& entityAlias); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.cpp index 6d3ddedd51..cd8fad1725 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.cpp @@ -176,10 +176,15 @@ namespace AzToolsFramework { PrefabDom& templateDomReference = m_prefabSystemComponentInterface->FindTemplateDom(templateId); + PrefabDomUtils::PrintPrefabDomValue("providedPatch", providedPatch); + PrefabDomUtils::PrintPrefabDomValue("templateDomReference", templateDomReference); + //apply patch to template AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::ApplyPatch(templateDomReference, templateDomReference.GetAllocator(), providedPatch, AZ::JsonMergeApproach::JsonPatch); + PrefabDomUtils::PrintPrefabDomValue("templateDomReference(Patch applied)", templateDomReference); + //trigger propagation if (result.GetOutcome() == AZ::JsonSerializationResult::Outcomes::Success) { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index 0181050a32..315c7b5710 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -986,6 +987,216 @@ namespace AzToolsFramework return AZ::Success(); } + PrefabOperationResult PrefabPublicHandler::DetachPrefabFromParent(const AZ::EntityId& entityId) + { + if (!entityId.IsValid()) + { + return AZ::Failure(AZStd::string("Cannot detach Prefab Instance with invalid container entity.")); + } + + if (IsLevelInstanceContainerEntity(entityId)) + { + return AZ::Failure(AZStd::string("Cannot detach level Prefab Instance.")); + } + + InstanceOptionalReference owningInstance = GetOwnerInstanceByEntityId(entityId); + if (owningInstance->get().GetContainerEntityId() != entityId) + { + return AZ::Failure(AZStd::string("Input entity should be its owning Instance's container entity.")); + } + + AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); + + UndoSystem::URSequencePoint* currentUndoBatch = nullptr; + ToolsApplicationRequests::Bus::BroadcastResult(currentUndoBatch, &ToolsApplicationRequests::Bus::Events::GetCurrentUndoBatch); + + bool createdUndo = false; + if (!currentUndoBatch) + { + createdUndo = true; + ToolsApplicationRequests::Bus::BroadcastResult( + currentUndoBatch, &ToolsApplicationRequests::Bus::Events::BeginUndoBatch, "Detach Prefab"); + AZ_Assert(currentUndoBatch, "Failed to create new undo batch."); + } + + // In order to undo Prefab Instance detachment, we have to create a selection command which selects the current selection + // and then add the detach as children. + // Commands always execute themselves first and then their children (when going forwards) + // and do the opposite when going backwards. + EntityIdList selectedEntities; + ToolsApplicationRequestBus::BroadcastResult(selectedEntities, &ToolsApplicationRequests::GetSelectedEntities); + SelectionCommand* selCommand = aznew SelectionCommand(selectedEntities, "Detach Prefab"); + + // We insert a "deselect all" command before we detach the Prefab Instance. This ensures the detach operations aren't changing + // selection state, which triggers expensive UI updates. By deselecting up front, we are able to do those expensive + // UI updates once at the start instead of once for each entity. + { + EntityIdList deselection; + SelectionCommand* deselectAllCommand = aznew SelectionCommand(deselection, "Deselect Entities"); + deselectAllCommand->SetParent(selCommand); + } + + { + AZ_PROFILE_SCOPE(AZ::Debug::ProfileCategory::AzToolsFramework, "Internal::DetachPrefab:UndoCapture"); + + InstanceOptionalReference parentInstance = owningInstance->get().GetParentInstance(); + const auto parentTemplateId = parentInstance->get().GetTemplateId(); + + Prefab::PrefabDom instanceDomBefore; + m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomBefore, parentInstance->get()); + + { + auto getInstancePtrResult = parentInstance->get().GetNestedInstance(owningInstance->get().GetInstanceAlias()); + AZ_Assert(getInstancePtrResult, "Can't find selected container entity's owning Instance."); + + auto& instancePtr = getInstancePtrResult->get(); + + AZStd::unordered_map oldEntityAliases; + oldEntityAliases.emplace(entityId, instancePtr->GetEntityAlias(entityId)->get()); + + auto containerEntityPtr = instancePtr->DetachContainerEntity(); + auto& containerEntity = *containerEntityPtr.release(); + auto editorPrefabComponent = containerEntity.FindComponent(); + containerEntity.Deactivate(); + const bool editorPrefabComponentRemoved = containerEntity.RemoveComponent(editorPrefabComponent); + AZ_Assert(editorPrefabComponentRemoved, "Remove EditorPrefabComponent failed."); + delete editorPrefabComponent; + containerEntity.Activate(); + + const bool containerEntityAdded = parentInstance->get().AddEntity(containerEntity); + AZ_Assert(containerEntityAdded, "Add target Instance's container entity to its parent Instance failed."); + + EntityIdList entityIds; + entityIds.emplace_back(containerEntity.GetId()); + + instancePtr->GetEntities( + [&](AZStd::unique_ptr& entityPtr) + { + oldEntityAliases.emplace(entityPtr->GetId(), instancePtr->GetEntityAlias(entityPtr->GetId())->get()); + return true; + }); + + instancePtr->DetachEntities( + [&](AZStd::unique_ptr entityPtr) + { + auto& entity = *entityPtr.release(); + const bool entityAdded = parentInstance->get().AddEntity(entity); + AZ_Assert(entityAdded, "Add target Instance's entity to its parent Instance failed."); + + entityIds.emplace_back(entity.GetId()); + }); + + Prefab::PrefabDom instanceDomAfter; + m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomAfter, parentInstance->get()); + + PrefabUndoInstance* command = aznew PrefabUndoInstance("Instance detachment"); + command->Capture(instanceDomBefore, instanceDomAfter, parentTemplateId); + command->SetParent(selCommand); + + selCommand->SetParent(currentUndoBatch); + { + AZ_PROFILE_SCOPE(AZ::Debug::ProfileCategory::AzToolsFramework, "Internal::DetachPrefab:RunRedo"); + selCommand->RunRedo(); + } + + const auto instanceTemplateId = instancePtr->GetTemplateId(); + auto parentContainerEntityId = parentInstance->get().GetContainerEntityId(); + instancePtr->GetNestedInstances( + [&](AZStd::unique_ptr& nestedInstancePtr) + { + //get previous link patch + auto linkRef = m_prefabSystemComponentInterface->FindLink(nestedInstancePtr->GetLinkId()); + PrefabDomValueReference linkPatches = linkRef->get().GetLinkPatches(); + AZ_Assert( + linkPatches.has_value(), "Unable to get patches on link with id '%llu' during prefab creation.", + nestedInstancePtr->GetLinkId()); + + PrefabDom linkPatchesCopy; + linkPatchesCopy.CopyFrom(linkPatches->get(), linkPatchesCopy.GetAllocator()); + + RemoveLink(nestedInstancePtr, instanceTemplateId, currentUndoBatch); + + /*auto getNestedInstanceContainerEntityResult = nestedInstancePtr->GetContainerEntity(); + AZ_Assert(getNestedInstanceContainerEntityResult.has_value(), "Can't get nested instance container entitt."); + + auto& nestedInstanceContainerEntity = getNestedInstanceContainerEntityResult->get(); + auto nestedInstanceContainerEntityId = nestedInstanceContainerEntity.GetId(); + + PrefabDom containerEntityDomBefore; + m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomBefore, nestedInstanceContainerEntity); + + AZ::TransformBus::Event(nestedInstanceContainerEntityId, &AZ::TransformInterface::SetParent, containerEntity.GetId()); + + PrefabDom containerEntityDomAfter; + m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomAfter, nestedInstanceContainerEntity); + + PrefabDom reparentPatch; + m_instanceToTemplateInterface->GeneratePatch(reparentPatch, containerEntityDomBefore, containerEntityDomAfter); + m_instanceToTemplateInterface->AppendEntityAliasToPatchPaths(reparentPatch, nestedInstanceContainerEntityId);*/ + + PrefabDomUtils::PrintPrefabDomValue("linkPatchesCopy", linkPatchesCopy); + + //update aliases + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + linkPatchesCopy.Accept(writer); + QString previousPatchString(buffer.GetString()); + + for (AZ::EntityId entityId : entityIds) + { + AZStd::string oldEntityAlias = oldEntityAliases[entityId]; + EntityAliasOptionalReference newEntityAlias = parentInstance->get().GetEntityAlias(entityId); + AZ_Assert( + newEntityAlias.has_value(), + "Could not fetch entity alias for entity with id '%llu' during prefab creation.", + static_cast(entityId)); + ReplaceOldAliases(previousPatchString, oldEntityAlias, newEntityAlias->get()); + } + + linkPatchesCopy.Parse(previousPatchString.toUtf8().constData()); + + CreateLink(*nestedInstancePtr, parentTemplateId, currentUndoBatch, AZStd::move(linkPatchesCopy), true); + + //update links? + //// Update the cache - this prevents these changes from being stored in the regular undo/redo nodes as a separate step + //m_prefabUndoCache.Store(nestedInstanceContainerEntityId, AZStd::move(containerEntityDomAfter)); + + //// Save these changes as patches to the link + //PrefabUndoLinkUpdate* linkUpdate = aznew PrefabUndoLinkUpdate(AZStd::to_string(static_cast(nestedInstanceContainerEntityId))); + //linkUpdate->SetParent(undoBatch.GetUndoBatch()); + //linkUpdate->Capture(reparentPatch, nestedInstance->GetLinkId()); + + //linkUpdate->Redo(); + }); + + RemoveLink(instancePtr, parentTemplateId, currentUndoBatch); + + AzToolsFramework::ToolsApplicationRequestBus::Broadcast( + &AzToolsFramework::ToolsApplicationRequestBus::Events::ClearDirtyEntities); + } + } + + if (createdUndo) + { + ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::EndUndoBatch); + } + + return AZ::Success(); + } + + void PrefabPublicHandler::ReplaceOldAliases(QString& stringToReplace, AZStd::string_view oldAlias, AZStd::string_view newAlias) + { + QString oldAliasQuotes = QString("\"%1\"").arg(oldAlias.data()); + QString newAliasQuotes = QString("\"%1\"").arg(newAlias.data()); + + stringToReplace.replace(oldAliasQuotes, newAliasQuotes); + + QString oldAliasPathRef = QString("/%1").arg(oldAlias.data()); + QString newAliasPathRef = QString("/%1").arg(newAlias.data()); + + stringToReplace.replace(oldAliasPathRef, newAliasPathRef); + } + void PrefabPublicHandler::GenerateContainerEntityTransform(const EntityList& topLevelEntities, AZ::Vector3& translation, AZ::Quaternion& rotation) { @@ -1236,18 +1447,5 @@ namespace AzToolsFramework return true; } - - void PrefabPublicHandler::ReplaceOldAliases(QString& stringToReplace, AZStd::string_view oldAlias, AZStd::string_view newAlias) - { - QString oldAliasQuotes = QString("\"%1\"").arg(oldAlias.data()); - QString newAliasQuotes = QString("\"%1\"").arg(newAlias.data()); - - stringToReplace.replace(oldAliasQuotes, newAliasQuotes); - - QString oldAliasPathRef = QString("/%1").arg(oldAlias.data()); - QString newAliasPathRef = QString("/%1").arg(newAlias.data()); - - stringToReplace.replace(oldAliasPathRef, newAliasPathRef); - } } // namespace Prefab } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h index 7e2357dd44..f1c32ee35c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h @@ -64,6 +64,8 @@ namespace AzToolsFramework PrefabOperationResult DeleteEntitiesAndAllDescendantsInInstance(const EntityIdList& entityIds) override; PrefabOperationResult DuplicateEntitiesInInstance(const EntityIdList& entityIds) override; + PrefabOperationResult DetachPrefabFromParent(const AZ::EntityId& entityId) override; + private: PrefabOperationResult DeleteFromInstance(const EntityIdList& entityIds, bool deleteDescendants); bool RetrieveAndSortPrefabEntitiesAndInstances(const EntityList& inputEntities, Instance& commonRootEntityOwningInstance, diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicInterface.h index 0750c4d264..f12bc359f2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicInterface.h @@ -150,6 +150,14 @@ namespace AzToolsFramework * @return An outcome object; on failure, it comes with an error message detailing the cause of the error. */ virtual PrefabOperationResult DuplicateEntitiesInInstance(const EntityIdList& entityIds) = 0; + + /** + * Detaches target container entity's owning instance from its parent instance. + * Bails if the entity is not a container entity or belongs to the level prefab instance. + * @param entityId The container entity whose instance to detach. + * @return An outcome object; on failure, it comes with an error message detailing the cause of the error. + */ + virtual PrefabOperationResult DetachPrefabFromParent(const AZ::EntityId& entityId) = 0; }; } // namespace Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp index 3edc190fb7..090c7bdc54 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp @@ -237,6 +237,27 @@ namespace AzToolsFramework { deleteAction->setDisabled(true); } + + QAction* detachPrefabAction = menu->addAction(QObject::tr("Detach Prefab...")); + if (selectedEntities.size() != 1) + { + detachPrefabAction->setDisabled(true); + } + else + { + AZ::EntityId selectedEntity = selectedEntities[0]; + + if (s_prefabPublicInterface->IsInstanceContainerEntity(selectedEntity) && + !s_prefabPublicInterface->IsLevelInstanceContainerEntity(selectedEntity)) + { + QObject::connect(detachPrefabAction, &QAction::triggered, detachPrefabAction, + [this, selectedEntity] { ContextMenu_DetachPrefab(selectedEntity); }); + } + else + { + detachPrefabAction->setDisabled(true); + } + } } void PrefabIntegrationManager::HandleSourceFileType(AZStd::string_view sourceFilePath, AZ::EntityId parentId, AZ::Vector3 position) const @@ -392,6 +413,17 @@ namespace AzToolsFramework } } + void PrefabIntegrationManager::ContextMenu_DetachPrefab(AZ::EntityId containerEntity) + { + PrefabOperationResult detachPrefabResult = + s_prefabPublicInterface->DetachPrefabFromParent(containerEntity); + + if (!detachPrefabResult.IsSuccess()) + { + WarnUserOfError("Detach Prefab error", detachPrefabResult.GetError()); + } + } + void PrefabIntegrationManager::GenerateSuggestedFilenameFromEntities(const EntityIdList& entityIds, AZStd::string& outName) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h index c9b846aa5b..69ec3013cc 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h @@ -93,6 +93,7 @@ namespace AzToolsFramework static void ContextMenu_EditPrefab(AZ::EntityId containerEntity); static void ContextMenu_SavePrefab(AZ::EntityId containerEntity); static void ContextMenu_DeleteSelected(); + static void ContextMenu_DetachPrefab(AZ::EntityId containerEntity); // Prompt and resolve dialogs static bool QueryUserForPrefabSaveLocation( From 4fc7d72b2b755fc8ccd7a1f4baee601015a96f4d Mon Sep 17 00:00:00 2001 From: chiyteng Date: Wed, 26 May 2021 16:49:09 -0700 Subject: [PATCH 02/14] modify DetachPrefabFromParent function for debugging --- .../Prefab/PrefabPublicHandler.cpp | 44 +++---------------- 1 file changed, 6 insertions(+), 38 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index 315c7b5710..d3553c78e1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -1042,14 +1042,14 @@ namespace AzToolsFramework InstanceOptionalReference parentInstance = owningInstance->get().GetParentInstance(); const auto parentTemplateId = parentInstance->get().GetTemplateId(); - Prefab::PrefabDom instanceDomBefore; - m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomBefore, parentInstance->get()); - { - auto getInstancePtrResult = parentInstance->get().GetNestedInstance(owningInstance->get().GetInstanceAlias()); - AZ_Assert(getInstancePtrResult, "Can't find selected container entity's owning Instance."); + auto instancePtr = parentInstance->get().DetachNestedInstance(owningInstance->get().GetInstanceAlias()); + AZ_Assert(instancePtr, "Can't detach selected Instance from its parent Instance."); - auto& instancePtr = getInstancePtrResult->get(); + RemoveLink(instancePtr, parentTemplateId, currentUndoBatch); + + Prefab::PrefabDom instanceDomBefore; + m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomBefore, parentInstance->get()); AZStd::unordered_map oldEntityAliases; oldEntityAliases.emplace(entityId, instancePtr->GetEntityAlias(entityId)->get()); @@ -1115,25 +1115,6 @@ namespace AzToolsFramework linkPatchesCopy.CopyFrom(linkPatches->get(), linkPatchesCopy.GetAllocator()); RemoveLink(nestedInstancePtr, instanceTemplateId, currentUndoBatch); - - /*auto getNestedInstanceContainerEntityResult = nestedInstancePtr->GetContainerEntity(); - AZ_Assert(getNestedInstanceContainerEntityResult.has_value(), "Can't get nested instance container entitt."); - - auto& nestedInstanceContainerEntity = getNestedInstanceContainerEntityResult->get(); - auto nestedInstanceContainerEntityId = nestedInstanceContainerEntity.GetId(); - - PrefabDom containerEntityDomBefore; - m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomBefore, nestedInstanceContainerEntity); - - AZ::TransformBus::Event(nestedInstanceContainerEntityId, &AZ::TransformInterface::SetParent, containerEntity.GetId()); - - PrefabDom containerEntityDomAfter; - m_instanceToTemplateInterface->GenerateDomForEntity(containerEntityDomAfter, nestedInstanceContainerEntity); - - PrefabDom reparentPatch; - m_instanceToTemplateInterface->GeneratePatch(reparentPatch, containerEntityDomBefore, containerEntityDomAfter); - m_instanceToTemplateInterface->AppendEntityAliasToPatchPaths(reparentPatch, nestedInstanceContainerEntityId);*/ - PrefabDomUtils::PrintPrefabDomValue("linkPatchesCopy", linkPatchesCopy); //update aliases @@ -1156,21 +1137,8 @@ namespace AzToolsFramework linkPatchesCopy.Parse(previousPatchString.toUtf8().constData()); CreateLink(*nestedInstancePtr, parentTemplateId, currentUndoBatch, AZStd::move(linkPatchesCopy), true); - - //update links? - //// Update the cache - this prevents these changes from being stored in the regular undo/redo nodes as a separate step - //m_prefabUndoCache.Store(nestedInstanceContainerEntityId, AZStd::move(containerEntityDomAfter)); - - //// Save these changes as patches to the link - //PrefabUndoLinkUpdate* linkUpdate = aznew PrefabUndoLinkUpdate(AZStd::to_string(static_cast(nestedInstanceContainerEntityId))); - //linkUpdate->SetParent(undoBatch.GetUndoBatch()); - //linkUpdate->Capture(reparentPatch, nestedInstance->GetLinkId()); - - //linkUpdate->Redo(); }); - RemoveLink(instancePtr, parentTemplateId, currentUndoBatch); - AzToolsFramework::ToolsApplicationRequestBus::Broadcast( &AzToolsFramework::ToolsApplicationRequestBus::Events::ClearDirtyEntities); } From 053e273b97bcacb191886afcad15c917addfa45c Mon Sep 17 00:00:00 2001 From: srikappa Date: Wed, 26 May 2021 18:24:49 -0700 Subject: [PATCH 03/14] Clear dirty entities at the end of InstantiatePrefab logic --- .../AzToolsFramework/Prefab/PrefabPublicHandler.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index d3553c78e1..1b98711352 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -384,7 +384,10 @@ namespace AzToolsFramework CreateLink(instanceToCreate->get(), instanceToParentUnder->get().GetTemplateId(), undoBatch.GetUndoBatch(), AZStd::move(patch)); // Update the cache - this prevents these changes from being stored in the regular undo/redo nodes - m_prefabUndoCache.Store(containerEntityId, AZStd::move(containerEntityDomAfter)); + //m_prefabUndoCache.Store(containerEntityId, AZStd::move(containerEntityDomAfter)); + + AzToolsFramework::ToolsApplicationRequestBus::Broadcast( + &AzToolsFramework::ToolsApplicationRequestBus::Events::ClearDirtyEntities); } return AZ::Success(); From c21a59af50933d1d0541de154b2ef154de3c6c44 Mon Sep 17 00:00:00 2001 From: chiyteng Date: Thu, 27 May 2021 17:19:32 -0700 Subject: [PATCH 04/14] Remove print dom for debug previously --- .../Prefab/Instance/InstanceToTemplatePropagator.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.cpp index cd8fad1725..6d3ddedd51 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceToTemplatePropagator.cpp @@ -176,15 +176,10 @@ namespace AzToolsFramework { PrefabDom& templateDomReference = m_prefabSystemComponentInterface->FindTemplateDom(templateId); - PrefabDomUtils::PrintPrefabDomValue("providedPatch", providedPatch); - PrefabDomUtils::PrintPrefabDomValue("templateDomReference", templateDomReference); - //apply patch to template AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::ApplyPatch(templateDomReference, templateDomReference.GetAllocator(), providedPatch, AZ::JsonMergeApproach::JsonPatch); - PrefabDomUtils::PrintPrefabDomValue("templateDomReference(Patch applied)", templateDomReference); - //trigger propagation if (result.GetOutcome() == AZ::JsonSerializationResult::Outcomes::Success) { From 57913d837854fafe4b47725266d62aaabc694f6e Mon Sep 17 00:00:00 2001 From: srikappa Date: Thu, 27 May 2021 18:19:28 -0700 Subject: [PATCH 05/14] A couple of bug fixes --- .../AzToolsFramework/Prefab/PrefabPublicHandler.cpp | 6 +++--- .../AzToolsFramework/Prefab/PrefabSystemComponent.cpp | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index 1b98711352..f6ded4ae45 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -1141,12 +1141,12 @@ namespace AzToolsFramework CreateLink(*nestedInstancePtr, parentTemplateId, currentUndoBatch, AZStd::move(linkPatchesCopy), true); }); - - AzToolsFramework::ToolsApplicationRequestBus::Broadcast( - &AzToolsFramework::ToolsApplicationRequestBus::Events::ClearDirtyEntities); } } + AzToolsFramework::ToolsApplicationRequestBus::Broadcast( + &AzToolsFramework::ToolsApplicationRequestBus::Events::ClearDirtyEntities); + if (createdUndo) { ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::EndUndoBatch); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp index c4e6415b02..1d478ad581 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp @@ -652,7 +652,8 @@ namespace AzToolsFramework if (instancesValue->get().FindMember(rapidjson::StringRef(instanceAlias.c_str())) == instancesValue->get().MemberEnd()) { instancesValue->get().AddMember( - rapidjson::StringRef(instanceAlias.c_str()), PrefabDomValue(), targetTemplateDom.GetAllocator()); + rapidjson::Value(instanceAlias.c_str(), targetTemplateDom.GetAllocator()), PrefabDomValue(), + targetTemplateDom.GetAllocator()); } Template& sourceTemplate = sourceTemplateRef->get(); From dc4a15628f4702d54035a7680dc3c68a478fcdf9 Mon Sep 17 00:00:00 2001 From: srikappa Date: Fri, 28 May 2021 00:43:31 -0700 Subject: [PATCH 06/14] Remove unused GetNestedInstance method in Prefab Instance class --- .../AzToolsFramework/Prefab/Instance/Instance.cpp | 11 ----------- .../AzToolsFramework/Prefab/Instance/Instance.h | 1 - 2 files changed, 12 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp index 8c7604f680..8f483ec818 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp @@ -401,17 +401,6 @@ namespace AzToolsFramework } } - InstancePtrOptionalReference Instance::GetNestedInstance(const InstanceAlias& instanceAlias) - { - auto nestedInstanceIterator = m_nestedInstances.find(instanceAlias); - if (nestedInstanceIterator != m_nestedInstances.end()) - { - return nestedInstanceIterator->second; - } - - return AZStd::nullopt; - } - void Instance::GetNestedInstances(const AZStd::function&)>& callback) { for (auto& [instanceAlias, instance] : m_nestedInstances) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h index 377be68753..31dfb7b8b4 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h @@ -95,7 +95,6 @@ namespace AzToolsFramework Instance& AddInstance(AZStd::unique_ptr instance); AZStd::unique_ptr DetachNestedInstance(const InstanceAlias& instanceAlias); - InstancePtrOptionalReference GetNestedInstance(const InstanceAlias& instanceAlias); /** * Gets the aliases for the entities in the Instance DOM. From be6cee806ddcc1b629cfcf3fad51c5429091a504 Mon Sep 17 00:00:00 2001 From: srikappa Date: Fri, 28 May 2021 02:14:28 -0700 Subject: [PATCH 07/14] Show detach prefab only when a single instance is selected --- .../Prefab/PrefabPublicHandler.cpp | 26 +++++++++---------- .../UI/Prefab/PrefabIntegrationManager.cpp | 21 +++++++-------- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index f6ded4ae45..653b7d4878 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -1155,19 +1155,6 @@ namespace AzToolsFramework return AZ::Success(); } - void PrefabPublicHandler::ReplaceOldAliases(QString& stringToReplace, AZStd::string_view oldAlias, AZStd::string_view newAlias) - { - QString oldAliasQuotes = QString("\"%1\"").arg(oldAlias.data()); - QString newAliasQuotes = QString("\"%1\"").arg(newAlias.data()); - - stringToReplace.replace(oldAliasQuotes, newAliasQuotes); - - QString oldAliasPathRef = QString("/%1").arg(oldAlias.data()); - QString newAliasPathRef = QString("/%1").arg(newAlias.data()); - - stringToReplace.replace(oldAliasPathRef, newAliasPathRef); - } - void PrefabPublicHandler::GenerateContainerEntityTransform(const EntityList& topLevelEntities, AZ::Vector3& translation, AZ::Quaternion& rotation) { @@ -1418,5 +1405,18 @@ namespace AzToolsFramework return true; } + + void PrefabPublicHandler::ReplaceOldAliases(QString& stringToReplace, AZStd::string_view oldAlias, AZStd::string_view newAlias) + { + QString oldAliasQuotes = QString("\"%1\"").arg(oldAlias.data()); + QString newAliasQuotes = QString("\"%1\"").arg(newAlias.data()); + + stringToReplace.replace(oldAliasQuotes, newAliasQuotes); + + QString oldAliasPathRef = QString("/%1").arg(oldAlias.data()); + QString newAliasPathRef = QString("/%1").arg(newAlias.data()); + + stringToReplace.replace(oldAliasPathRef, newAliasPathRef); + } } // namespace Prefab } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp index 090c7bdc54..45499a4071 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp @@ -238,24 +238,21 @@ namespace AzToolsFramework deleteAction->setDisabled(true); } - QAction* detachPrefabAction = menu->addAction(QObject::tr("Detach Prefab...")); - if (selectedEntities.size() != 1) - { - detachPrefabAction->setDisabled(true); - } - else + // Detach Prefab + if (selectedEntities.size() == 1) { AZ::EntityId selectedEntity = selectedEntities[0]; if (s_prefabPublicInterface->IsInstanceContainerEntity(selectedEntity) && !s_prefabPublicInterface->IsLevelInstanceContainerEntity(selectedEntity)) { - QObject::connect(detachPrefabAction, &QAction::triggered, detachPrefabAction, - [this, selectedEntity] { ContextMenu_DetachPrefab(selectedEntity); }); - } - else - { - detachPrefabAction->setDisabled(true); + QAction* detachPrefabAction = menu->addAction(QObject::tr("Detach Prefab...")); + QObject::connect( + detachPrefabAction, &QAction::triggered, detachPrefabAction, + [this, selectedEntity] + { + ContextMenu_DetachPrefab(selectedEntity); + }); } } } From 55e1da64bb2e95a6668fd919619334a74ebb8d90 Mon Sep 17 00:00:00 2001 From: srikappa Date: Fri, 28 May 2021 02:29:09 -0700 Subject: [PATCH 08/14] Renamed a function and improved comments --- .../AzToolsFramework/Prefab/Instance/Instance.h | 1 - .../AzToolsFramework/Prefab/PrefabPublicHandler.cpp | 2 +- .../AzToolsFramework/Prefab/PrefabPublicHandler.h | 2 +- .../AzToolsFramework/Prefab/PrefabPublicInterface.h | 9 ++++++--- .../UI/Prefab/PrefabIntegrationManager.cpp | 2 +- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h index 31dfb7b8b4..68bc395012 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h @@ -48,7 +48,6 @@ namespace AzToolsFramework using EntityAliasOptionalReference = AZStd::optional>; using InstanceOptionalReference = AZStd::optional>; using InstanceOptionalConstReference = AZStd::optional>; - using InstancePtrOptionalReference = AZStd::optional>>; using InstanceSet = AZStd::unordered_set; using InstanceSetConstReference = AZStd::optional>; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index 653b7d4878..7ec0ddf8ad 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -990,7 +990,7 @@ namespace AzToolsFramework return AZ::Success(); } - PrefabOperationResult PrefabPublicHandler::DetachPrefabFromParent(const AZ::EntityId& entityId) + PrefabOperationResult PrefabPublicHandler::DetachPrefab(const AZ::EntityId& entityId) { if (!entityId.IsValid()) { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h index f1c32ee35c..f3b3b242dd 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h @@ -64,7 +64,7 @@ namespace AzToolsFramework PrefabOperationResult DeleteEntitiesAndAllDescendantsInInstance(const EntityIdList& entityIds) override; PrefabOperationResult DuplicateEntitiesInInstance(const EntityIdList& entityIds) override; - PrefabOperationResult DetachPrefabFromParent(const AZ::EntityId& entityId) override; + PrefabOperationResult DetachPrefab(const AZ::EntityId& entityId) override; private: PrefabOperationResult DeleteFromInstance(const EntityIdList& entityIds, bool deleteDescendants); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicInterface.h index f12bc359f2..ec13a852ee 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicInterface.h @@ -152,12 +152,15 @@ namespace AzToolsFramework virtual PrefabOperationResult DuplicateEntitiesInInstance(const EntityIdList& entityIds) = 0; /** - * Detaches target container entity's owning instance from its parent instance. + * If the entity id is a container entity id, detaches the prefab instance corresponding to it. This includes converting + * the container entity into a regular entity and putting it under the parent prefab, removing the link between this + * instance and the parent, removing links between this instance and it's nested instances, adding entities directly + * owned by this instance under the parent instance. * Bails if the entity is not a container entity or belongs to the level prefab instance. - * @param entityId The container entity whose instance to detach. + * @param entityId The container entity id of the instance to detach. * @return An outcome object; on failure, it comes with an error message detailing the cause of the error. */ - virtual PrefabOperationResult DetachPrefabFromParent(const AZ::EntityId& entityId) = 0; + virtual PrefabOperationResult DetachPrefab(const AZ::EntityId& entityId) = 0; }; } // namespace Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp index 45499a4071..b7feb1a8c1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp @@ -413,7 +413,7 @@ namespace AzToolsFramework void PrefabIntegrationManager::ContextMenu_DetachPrefab(AZ::EntityId containerEntity) { PrefabOperationResult detachPrefabResult = - s_prefabPublicInterface->DetachPrefabFromParent(containerEntity); + s_prefabPublicInterface->DetachPrefab(containerEntity); if (!detachPrefabResult.IsSuccess()) { From 984db9c1b48571998f5a19381262ce391ed2727d Mon Sep 17 00:00:00 2001 From: chiyteng Date: Fri, 28 May 2021 10:56:03 -0700 Subject: [PATCH 09/14] Remove selection command and update undo batch in DetachPrefab function --- .../Prefab/PrefabPublicHandler.cpp | 53 ++++--------------- 1 file changed, 10 insertions(+), 43 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index 7ec0ddf8ad..e223775add 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -1010,38 +1010,11 @@ namespace AzToolsFramework AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); - UndoSystem::URSequencePoint* currentUndoBatch = nullptr; - ToolsApplicationRequests::Bus::BroadcastResult(currentUndoBatch, &ToolsApplicationRequests::Bus::Events::GetCurrentUndoBatch); - - bool createdUndo = false; - if (!currentUndoBatch) - { - createdUndo = true; - ToolsApplicationRequests::Bus::BroadcastResult( - currentUndoBatch, &ToolsApplicationRequests::Bus::Events::BeginUndoBatch, "Detach Prefab"); - AZ_Assert(currentUndoBatch, "Failed to create new undo batch."); - } - - // In order to undo Prefab Instance detachment, we have to create a selection command which selects the current selection - // and then add the detach as children. - // Commands always execute themselves first and then their children (when going forwards) - // and do the opposite when going backwards. - EntityIdList selectedEntities; - ToolsApplicationRequestBus::BroadcastResult(selectedEntities, &ToolsApplicationRequests::GetSelectedEntities); - SelectionCommand* selCommand = aznew SelectionCommand(selectedEntities, "Detach Prefab"); - - // We insert a "deselect all" command before we detach the Prefab Instance. This ensures the detach operations aren't changing - // selection state, which triggers expensive UI updates. By deselecting up front, we are able to do those expensive - // UI updates once at the start instead of once for each entity. - { - EntityIdList deselection; - SelectionCommand* deselectAllCommand = aznew SelectionCommand(deselection, "Deselect Entities"); - deselectAllCommand->SetParent(selCommand); - } - { AZ_PROFILE_SCOPE(AZ::Debug::ProfileCategory::AzToolsFramework, "Internal::DetachPrefab:UndoCapture"); + ScopedUndoBatch undoBatch("Detach Prefab"); + InstanceOptionalReference parentInstance = owningInstance->get().GetParentInstance(); const auto parentTemplateId = parentInstance->get().GetTemplateId(); @@ -1049,7 +1022,7 @@ namespace AzToolsFramework auto instancePtr = parentInstance->get().DetachNestedInstance(owningInstance->get().GetInstanceAlias()); AZ_Assert(instancePtr, "Can't detach selected Instance from its parent Instance."); - RemoveLink(instancePtr, parentTemplateId, currentUndoBatch); + RemoveLink(instancePtr, parentTemplateId, undoBatch.GetUndoBatch()); Prefab::PrefabDom instanceDomBefore; m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomBefore, parentInstance->get()); @@ -1094,12 +1067,10 @@ namespace AzToolsFramework PrefabUndoInstance* command = aznew PrefabUndoInstance("Instance detachment"); command->Capture(instanceDomBefore, instanceDomAfter, parentTemplateId); - command->SetParent(selCommand); - - selCommand->SetParent(currentUndoBatch); + command->SetParent(undoBatch.GetUndoBatch()); { AZ_PROFILE_SCOPE(AZ::Debug::ProfileCategory::AzToolsFramework, "Internal::DetachPrefab:RunRedo"); - selCommand->RunRedo(); + command->RunRedo(); } const auto instanceTemplateId = instancePtr->GetTemplateId(); @@ -1117,7 +1088,7 @@ namespace AzToolsFramework PrefabDom linkPatchesCopy; linkPatchesCopy.CopyFrom(linkPatches->get(), linkPatchesCopy.GetAllocator()); - RemoveLink(nestedInstancePtr, instanceTemplateId, currentUndoBatch); + RemoveLink(nestedInstancePtr, instanceTemplateId, undoBatch.GetUndoBatch()); PrefabDomUtils::PrintPrefabDomValue("linkPatchesCopy", linkPatchesCopy); //update aliases @@ -1139,17 +1110,13 @@ namespace AzToolsFramework linkPatchesCopy.Parse(previousPatchString.toUtf8().constData()); - CreateLink(*nestedInstancePtr, parentTemplateId, currentUndoBatch, AZStd::move(linkPatchesCopy), true); + CreateLink(*nestedInstancePtr, parentTemplateId, undoBatch.GetUndoBatch(), + AZStd::move(linkPatchesCopy), true); }); } - } - AzToolsFramework::ToolsApplicationRequestBus::Broadcast( - &AzToolsFramework::ToolsApplicationRequestBus::Events::ClearDirtyEntities); - - if (createdUndo) - { - ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::EndUndoBatch); + AzToolsFramework::ToolsApplicationRequestBus::Broadcast( + &AzToolsFramework::ToolsApplicationRequestBus::Events::ClearDirtyEntities); } return AZ::Success(); From de4cfdb5d7d7ef8c736763eb366013640e6d00b5 Mon Sep 17 00:00:00 2001 From: chiyteng Date: Fri, 28 May 2021 11:33:58 -0700 Subject: [PATCH 10/14] Add helper function to update entity aliases in link patch --- .../Prefab/PrefabPublicHandler.cpp | 67 +++++++++++-------- .../Prefab/PrefabPublicHandler.h | 7 +- 2 files changed, 45 insertions(+), 29 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index e223775add..1c645100d1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -189,24 +189,7 @@ namespace AzToolsFramework if (nestedInstanceLinkPatchesMap.contains(nestedInstance.get())) { previousPatch = AZStd::move(nestedInstanceLinkPatchesMap[nestedInstance.get()]); - rapidjson::StringBuffer buffer; - rapidjson::Writer writer(buffer); - previousPatch.Accept(writer); - QString previousPatchString(buffer.GetString()); - - for (AZ::Entity* entity : entities) - { - AZ::EntityId entityId = entity->GetId(); - AZStd::string oldEntityAlias = oldEntityAliases[entityId]; - EntityAliasOptionalReference newEntityAlias = instanceToCreate->get().GetEntityAlias(entityId); - AZ_Assert( - newEntityAlias.has_value(), - "Could not fetch entity alias for entity with id '%llu' during prefab creation.", - static_cast(entityId)); - ReplaceOldAliases(previousPatchString, oldEntityAlias, newEntityAlias->get()); - } - - previousPatch.Parse(previousPatchString.toUtf8().constData()); + UpdateLinkPatchForNewParent(previousPatch, oldEntityAliases, instanceToCreate->get()); } // These link creations shouldn't be undone because that would put the template in a non-usable state if a user @@ -1015,17 +998,20 @@ namespace AzToolsFramework ScopedUndoBatch undoBatch("Detach Prefab"); - InstanceOptionalReference parentInstance = owningInstance->get().GetParentInstance(); - const auto parentTemplateId = parentInstance->get().GetTemplateId(); + InstanceOptionalReference getParentInstanceResult = owningInstance->get().GetParentInstance(); + AZ_Assert(getParentInstanceResult.has_value(), "Can't get parent Instance from Instance of given container entity."); + + auto& parentInstance = getParentInstanceResult->get(); + const auto parentTemplateId = parentInstance.GetTemplateId(); { - auto instancePtr = parentInstance->get().DetachNestedInstance(owningInstance->get().GetInstanceAlias()); + auto instancePtr = parentInstance.DetachNestedInstance(owningInstance->get().GetInstanceAlias()); AZ_Assert(instancePtr, "Can't detach selected Instance from its parent Instance."); RemoveLink(instancePtr, parentTemplateId, undoBatch.GetUndoBatch()); Prefab::PrefabDom instanceDomBefore; - m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomBefore, parentInstance->get()); + m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomBefore, parentInstance); AZStd::unordered_map oldEntityAliases; oldEntityAliases.emplace(entityId, instancePtr->GetEntityAlias(entityId)->get()); @@ -1039,7 +1025,7 @@ namespace AzToolsFramework delete editorPrefabComponent; containerEntity.Activate(); - const bool containerEntityAdded = parentInstance->get().AddEntity(containerEntity); + const bool containerEntityAdded = parentInstance.AddEntity(containerEntity); AZ_Assert(containerEntityAdded, "Add target Instance's container entity to its parent Instance failed."); EntityIdList entityIds; @@ -1056,14 +1042,14 @@ namespace AzToolsFramework [&](AZStd::unique_ptr entityPtr) { auto& entity = *entityPtr.release(); - const bool entityAdded = parentInstance->get().AddEntity(entity); + const bool entityAdded = parentInstance.AddEntity(entity); AZ_Assert(entityAdded, "Add target Instance's entity to its parent Instance failed."); entityIds.emplace_back(entity.GetId()); }); Prefab::PrefabDom instanceDomAfter; - m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomAfter, parentInstance->get()); + m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomAfter, parentInstance); PrefabUndoInstance* command = aznew PrefabUndoInstance("Instance detachment"); command->Capture(instanceDomBefore, instanceDomAfter, parentTemplateId); @@ -1074,7 +1060,7 @@ namespace AzToolsFramework } const auto instanceTemplateId = instancePtr->GetTemplateId(); - auto parentContainerEntityId = parentInstance->get().GetContainerEntityId(); + auto parentContainerEntityId = parentInstance.GetContainerEntityId(); instancePtr->GetNestedInstances( [&](AZStd::unique_ptr& nestedInstancePtr) { @@ -1089,8 +1075,8 @@ namespace AzToolsFramework linkPatchesCopy.CopyFrom(linkPatches->get(), linkPatchesCopy.GetAllocator()); RemoveLink(nestedInstancePtr, instanceTemplateId, undoBatch.GetUndoBatch()); - PrefabDomUtils::PrintPrefabDomValue("linkPatchesCopy", linkPatchesCopy); + UpdateLinkPatchForNewParent(linkPatchesCopy, oldEntityAliases, parentInstance); //update aliases rapidjson::StringBuffer buffer; rapidjson::Writer writer(buffer); @@ -1100,7 +1086,7 @@ namespace AzToolsFramework for (AZ::EntityId entityId : entityIds) { AZStd::string oldEntityAlias = oldEntityAliases[entityId]; - EntityAliasOptionalReference newEntityAlias = parentInstance->get().GetEntityAlias(entityId); + EntityAliasOptionalReference newEntityAlias = parentInstance.GetEntityAlias(entityId); AZ_Assert( newEntityAlias.has_value(), "Could not fetch entity alias for entity with id '%llu' during prefab creation.", @@ -1385,5 +1371,30 @@ namespace AzToolsFramework stringToReplace.replace(oldAliasPathRef, newAliasPathRef); } + + void PrefabPublicHandler::UpdateLinkPatchForNewParent( + PrefabDom& linkPatch, + const AZStd::unordered_map& oldEntityAliases, + Instance& newParent) + { + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + linkPatch.Accept(writer); + QString previousPatchString(buffer.GetString()); + + for (const auto& [entityId, oldEntityAlias] : oldEntityAliases) + { + EntityAliasOptionalReference newEntityAlias = newParent.GetEntityAlias(entityId); + AZ_Assert( + newEntityAlias.has_value(), + "Could not fetch entity alias for entity with id '%llu' during prefab creation.", + static_cast(entityId)); + + ReplaceOldAliases(previousPatchString, oldEntityAlias, newEntityAlias->get()); + } + + linkPatch.Parse(previousPatchString.toUtf8().constData()); + } + } // namespace Prefab } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h index f3b3b242dd..c339c17a48 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h @@ -134,7 +134,12 @@ namespace AzToolsFramework bool IsCyclicalDependencyFound( InstanceOptionalConstReference instance, const AZStd::unordered_set& templateSourcePaths); - void ReplaceOldAliases(QString& stringToReplace, AZStd::string_view oldAlias, AZStd::string_view newAlias); + static void UpdateLinkPatchForNewParent( + PrefabDom& linkPatch, + const AZStd::unordered_map& oldEntityAliases, + Instance& newParent); + + static void ReplaceOldAliases(QString& stringToReplace, AZStd::string_view oldAlias, AZStd::string_view newAlias); static Instance* GetParentInstance(Instance* instance); static Instance* GetAncestorOfInstanceThatIsChildOfRoot(const Instance* ancestor, Instance* descendant); From da0ab84f1cbd279294eab50ea832e5122f06e147 Mon Sep 17 00:00:00 2001 From: chiyteng Date: Fri, 28 May 2021 11:42:36 -0700 Subject: [PATCH 11/14] Add helper function to update entity aliases in link patch --- .../Prefab/PrefabPublicHandler.cpp | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index 1c645100d1..fdc4302c1b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -1077,25 +1077,7 @@ namespace AzToolsFramework RemoveLink(nestedInstancePtr, instanceTemplateId, undoBatch.GetUndoBatch()); UpdateLinkPatchForNewParent(linkPatchesCopy, oldEntityAliases, parentInstance); - //update aliases - rapidjson::StringBuffer buffer; - rapidjson::Writer writer(buffer); - linkPatchesCopy.Accept(writer); - QString previousPatchString(buffer.GetString()); - - for (AZ::EntityId entityId : entityIds) - { - AZStd::string oldEntityAlias = oldEntityAliases[entityId]; - EntityAliasOptionalReference newEntityAlias = parentInstance.GetEntityAlias(entityId); - AZ_Assert( - newEntityAlias.has_value(), - "Could not fetch entity alias for entity with id '%llu' during prefab creation.", - static_cast(entityId)); - ReplaceOldAliases(previousPatchString, oldEntityAlias, newEntityAlias->get()); - } - - linkPatchesCopy.Parse(previousPatchString.toUtf8().constData()); - + CreateLink(*nestedInstancePtr, parentTemplateId, undoBatch.GetUndoBatch(), AZStd::move(linkPatchesCopy), true); }); From e8e9096dda7ea79d6275f26db4eb0dbf8eb82932 Mon Sep 17 00:00:00 2001 From: srikappa Date: Tue, 1 Jun 2021 11:11:13 -0700 Subject: [PATCH 12/14] Changed a function name and removed a comment --- .../AzToolsFramework/Prefab/PrefabPublicHandler.cpp | 9 +++------ .../AzToolsFramework/Prefab/PrefabPublicHandler.h | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index fdc4302c1b..3187b55721 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -189,7 +189,7 @@ namespace AzToolsFramework if (nestedInstanceLinkPatchesMap.contains(nestedInstance.get())) { previousPatch = AZStd::move(nestedInstanceLinkPatchesMap[nestedInstance.get()]); - UpdateLinkPatchForNewParent(previousPatch, oldEntityAliases, instanceToCreate->get()); + UpdateLinkPatchesWithNewEntityAliases(previousPatch, oldEntityAliases, instanceToCreate->get()); } // These link creations shouldn't be undone because that would put the template in a non-usable state if a user @@ -366,9 +366,6 @@ namespace AzToolsFramework CreateLink(instanceToCreate->get(), instanceToParentUnder->get().GetTemplateId(), undoBatch.GetUndoBatch(), AZStd::move(patch)); - // Update the cache - this prevents these changes from being stored in the regular undo/redo nodes - //m_prefabUndoCache.Store(containerEntityId, AZStd::move(containerEntityDomAfter)); - AzToolsFramework::ToolsApplicationRequestBus::Broadcast( &AzToolsFramework::ToolsApplicationRequestBus::Events::ClearDirtyEntities); } @@ -1076,7 +1073,7 @@ namespace AzToolsFramework RemoveLink(nestedInstancePtr, instanceTemplateId, undoBatch.GetUndoBatch()); - UpdateLinkPatchForNewParent(linkPatchesCopy, oldEntityAliases, parentInstance); + UpdateLinkPatchesWithNewEntityAliases(linkPatchesCopy, oldEntityAliases, parentInstance); CreateLink(*nestedInstancePtr, parentTemplateId, undoBatch.GetUndoBatch(), AZStd::move(linkPatchesCopy), true); @@ -1354,7 +1351,7 @@ namespace AzToolsFramework stringToReplace.replace(oldAliasPathRef, newAliasPathRef); } - void PrefabPublicHandler::UpdateLinkPatchForNewParent( + void PrefabPublicHandler::UpdateLinkPatchesWithNewEntityAliases( PrefabDom& linkPatch, const AZStd::unordered_map& oldEntityAliases, Instance& newParent) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h index c339c17a48..acaf9b5753 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h @@ -134,7 +134,7 @@ namespace AzToolsFramework bool IsCyclicalDependencyFound( InstanceOptionalConstReference instance, const AZStd::unordered_set& templateSourcePaths); - static void UpdateLinkPatchForNewParent( + void UpdateLinkPatchesWithNewEntityAliases( PrefabDom& linkPatch, const AZStd::unordered_map& oldEntityAliases, Instance& newParent); From 9fd690f0048a2d84abdec52271346ab86c28d553 Mon Sep 17 00:00:00 2001 From: srikappa Date: Tue, 1 Jun 2021 17:03:50 -0700 Subject: [PATCH 13/14] Changed a function parameter name --- .../AzToolsFramework/Prefab/PrefabPublicHandler.cpp | 12 ++++++------ .../AzToolsFramework/Prefab/PrefabPublicHandler.h | 2 +- .../AzToolsFramework/Prefab/PrefabPublicInterface.h | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index afda2aef09..b44d8fde14 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -973,20 +973,20 @@ namespace AzToolsFramework return AZ::Success(); } - PrefabOperationResult PrefabPublicHandler::DetachPrefab(const AZ::EntityId& entityId) + PrefabOperationResult PrefabPublicHandler::DetachPrefab(const AZ::EntityId& containerEntityId) { - if (!entityId.IsValid()) + if (!containerEntityId.IsValid()) { return AZ::Failure(AZStd::string("Cannot detach Prefab Instance with invalid container entity.")); } - if (IsLevelInstanceContainerEntity(entityId)) + if (IsLevelInstanceContainerEntity(containerEntityId)) { return AZ::Failure(AZStd::string("Cannot detach level Prefab Instance.")); } - InstanceOptionalReference owningInstance = GetOwnerInstanceByEntityId(entityId); - if (owningInstance->get().GetContainerEntityId() != entityId) + InstanceOptionalReference owningInstance = GetOwnerInstanceByEntityId(containerEntityId); + if (owningInstance->get().GetContainerEntityId() != containerEntityId) { return AZ::Failure(AZStd::string("Input entity should be its owning Instance's container entity.")); } @@ -1014,7 +1014,7 @@ namespace AzToolsFramework m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomBefore, parentInstance); AZStd::unordered_map oldEntityAliases; - oldEntityAliases.emplace(entityId, instancePtr->GetEntityAlias(entityId)->get()); + oldEntityAliases.emplace(containerEntityId, instancePtr->GetEntityAlias(containerEntityId)->get()); auto containerEntityPtr = instancePtr->DetachContainerEntity(); auto& containerEntity = *containerEntityPtr.release(); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h index f73af93195..e7b6f8c932 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h @@ -64,7 +64,7 @@ namespace AzToolsFramework PrefabOperationResult DeleteEntitiesAndAllDescendantsInInstance(const EntityIdList& entityIds) override; PrefabOperationResult DuplicateEntitiesInInstance(const EntityIdList& entityIds) override; - PrefabOperationResult DetachPrefab(const AZ::EntityId& entityId) override; + PrefabOperationResult DetachPrefab(const AZ::EntityId& containerEntityId) override; private: PrefabOperationResult DeleteFromInstance(const EntityIdList& entityIds, bool deleteDescendants); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicInterface.h index ad6a28cb3e..1dbed53223 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicInterface.h @@ -157,10 +157,10 @@ namespace AzToolsFramework * instance and the parent, removing links between this instance and it's nested instances, adding entities directly * owned by this instance under the parent instance. * Bails if the entity is not a container entity or belongs to the level prefab instance. - * @param entityId The container entity id of the instance to detach. + * @param containerEntityId The container entity id of the instance to detach. * @return An outcome object; on failure, it comes with an error message detailing the cause of the error. */ - virtual PrefabOperationResult DetachPrefab(const AZ::EntityId& entityId) = 0; + virtual PrefabOperationResult DetachPrefab(const AZ::EntityId& containerEntityId) = 0; }; } // namespace Prefab From f1dbeb584af8e2671a056baee74e645bab5382f0 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Wed, 2 Jun 2021 16:50:18 -0700 Subject: [PATCH 14/14] LYN-4206 CMake bakes install prefix during configure (#1100) --- cmake/Platform/Common/Install_common.cmake | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index b18aed6fb4..710a8b266f 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -15,7 +15,11 @@ ly_set(LY_DEFAULT_INSTALL_COMPONENT Core) file(RELATIVE_PATH runtime_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) file(RELATIVE_PATH library_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) -set(install_output_folder "${CMAKE_INSTALL_PREFIX}/${runtime_output_directory}/${PAL_PLATFORM_NAME}/$") +# Anywhere CMAKE_INSTALL_PREFIX is used, it has to be escaped so it is baked into the cmake_install.cmake script instead +# of baking the path. This is needed so `cmake --install --prefix ` works regardless of the CMAKE_INSTALL_PREFIX +# used to generate the solution. +# CMAKE_INSTALL_PREFIX is still used when building the INSTALL target +set(install_output_folder "\${CMAKE_INSTALL_PREFIX}/${runtime_output_directory}/${PAL_PLATFORM_NAME}/$") #! ly_setup_target: Setup the data needed to re-create the cmake target commands for a single target