diff --git a/Code/Framework/AzCore/AzCore/Slice/SliceComponent.cpp b/Code/Framework/AzCore/AzCore/Slice/SliceComponent.cpp index 592989ebda..2340d7c786 100644 --- a/Code/Framework/AzCore/AzCore/Slice/SliceComponent.cpp +++ b/Code/Framework/AzCore/AzCore/Slice/SliceComponent.cpp @@ -1740,7 +1740,10 @@ namespace AZ if (!iter->IsInstantiated()) { #if defined(AZ_ENABLE_TRACING) - Data::Asset thisAsset = Data::AssetManager::Instance().FindAsset(GetMyAsset()->GetId(), AZ::Data::AssetLoadBehavior::Default); + Data::Asset thisAsset = GetMyAsset() + ? Data::Asset(Data::AssetManager::Instance().FindAsset( + GetMyAsset()->GetId(), AZ::Data::AssetLoadBehavior::Default)) + : Data::Asset(); AZ_Warning("Slice", false, "Removing %d instances of slice asset %s from parent asset %s due to failed instantiation. " "Saving parent asset will result in loss of slice data.", iter->GetInstances().size(), diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp index eb247369c5..c4cb3e0316 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.cpp @@ -80,6 +80,12 @@ namespace AzToolsFramework void Instance::SetTemplateId(const TemplateId& templateId) { + // If we aren't changing the template Id, there's no need to unregister / re-register + if (templateId == m_templateId) + { + return; + } + // If this instance's templateId is valid, we should be able to unregister this instance from // Template to Instance mapping successfully. if (m_templateId != InvalidTemplateId && diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.cpp index 80ac86c974..fa03ab22e5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.cpp @@ -72,10 +72,18 @@ namespace AzToolsFramework for (auto instance : findInstancesResult->get()) { - m_instancesUpdateQueue.emplace(instance); + m_instancesUpdateQueue.emplace_back(instance); } } + void InstanceUpdateExecutor::RemoveTemplateInstanceFromQueue(const Instance* instance) + { + AZStd::erase_if(m_instancesUpdateQueue, [instance](Instance* entry) + { + return entry == instance; + }); + } + bool InstanceUpdateExecutor::UpdateTemplateInstancesInQueue() { bool isUpdateSuccessful = true; @@ -97,9 +105,16 @@ namespace AzToolsFramework ToolsApplicationRequestBus::BroadcastResult(selectedEntityIds, &ToolsApplicationRequests::GetSelectedEntities); ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequests::SetSelectedEntities, EntityIdList()); - for (int i = 0; i < instanceCountToUpdateInBatch; ++i) + // Process all instances in the queue, capped to the batch size. + // Even though we potentially initialized the batch size to the queue, it's possible for the queue size to shrink + // during instance processing if the instance gets deleted and it was queued multiple times. To handle this, we + // make sure to end the loop once the queue is empty, regardless of what the initial size was. + for (int i = 0; (i < instanceCountToUpdateInBatch) && !m_instancesUpdateQueue.empty(); ++i) { Instance* instanceToUpdate = m_instancesUpdateQueue.front(); + m_instancesUpdateQueue.pop_front(); + AZ_Assert(instanceToUpdate != nullptr, "Invalid instance on update queue."); + TemplateId instanceTemplateId = instanceToUpdate->GetTemplateId(); if (currentTemplateId != instanceTemplateId) { @@ -115,7 +130,6 @@ namespace AzToolsFramework // Remove the instance from update queue if its corresponding template couldn't be found isUpdateSuccessful = false; - m_instancesUpdateQueue.pop(); continue; } } @@ -127,7 +141,6 @@ namespace AzToolsFramework // Since nested instances get reconstructed during propagation, remove any nested instance that no longer // maps to a template. isUpdateSuccessful = false; - m_instancesUpdateQueue.pop(); continue; } @@ -148,8 +161,6 @@ namespace AzToolsFramework isUpdateSuccessful = false; } - - m_instancesUpdateQueue.pop(); } for (auto entityIdIterator = selectedEntityIds.begin(); entityIdIterator != selectedEntityIds.end(); entityIdIterator++) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.h index 04bd189816..fa13c34b98 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutor.h @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include @@ -37,6 +37,7 @@ namespace AzToolsFramework void AddTemplateInstancesToQueue(TemplateId instanceTemplateId) override; bool UpdateTemplateInstancesInQueue() override; + virtual void RemoveTemplateInstanceFromQueue(const Instance* instance) override; void RegisterInstanceUpdateExecutorInterface(); void UnregisterInstanceUpdateExecutorInterface(); @@ -45,7 +46,7 @@ namespace AzToolsFramework PrefabSystemComponentInterface* m_prefabSystemComponentInterface = nullptr; TemplateInstanceMapperInterface* m_templateInstanceMapperInterface = nullptr; int m_instanceCountToUpdateInBatch = 0; - AZStd::queue m_instancesUpdateQueue; + AZStd::deque m_instancesUpdateQueue; bool m_updatingTemplateInstancesInQueue { false }; }; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutorInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutorInterface.h index 9ee636e161..d794c4929d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutorInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceUpdateExecutorInterface.h @@ -31,6 +31,9 @@ namespace AzToolsFramework // Update Instances in the waiting queue. virtual bool UpdateTemplateInstancesInQueue() = 0; + + // Remove an Instance from the waiting queue. + virtual void RemoveTemplateInstanceFromQueue(const Instance* instance) = 0; }; } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapper.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapper.cpp index 7540be0cfa..2012649941 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapper.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/TemplateInstanceMapper.cpp @@ -14,6 +14,7 @@ #include #include +#include namespace AzToolsFramework { @@ -71,6 +72,12 @@ namespace AzToolsFramework bool TemplateInstanceMapper::UnregisterInstance(Instance& instance) { + // The InstanceUpdateExecutor queries the TemplateInstanceMapper for a list of instances related to a template. + // Consequently, if an instance gets unregistered for a template, we need to notify the InstanceUpdateExecutor as well + // so that it clears any internal associations that it might have in its queue. + AZ_Assert(AZ::Interface::Get() != nullptr, "InstanceUpdateExecutor doesn't exist"); + AZ::Interface::Get()->RemoveTemplateInstanceFromQueue(&instance); + auto found = m_templateIdToInstancesMap.find(instance.GetTemplateId()); return found != m_templateIdToInstancesMap.end() && found->second.erase(&instance) != 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp index 8192e86956..519b6d0b26 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp @@ -162,6 +162,12 @@ namespace AzToolsFramework classElement.RemoveElementByName(AZ_CRC("InterpolateScale", 0x9d00b831)); } + if (classElement.GetVersion() < 10) + { + // The "Sync Enabled" flag is no longer needed. + classElement.RemoveElementByName(AZ_CRC_CE("Sync Enabled")); + } + return true; } } // namespace Internal @@ -1305,7 +1311,7 @@ namespace AzToolsFramework Field("IsStatic", &TransformComponent::m_isStatic)-> Field("InterpolatePosition", &TransformComponent::m_interpolatePosition)-> Field("InterpolateRotation", &TransformComponent::m_interpolateRotation)-> - Version(9, &Internal::TransformComponentDataConverter); + Version(10, &Internal::TransformComponentDataConverter); if (AZ::EditContext* ptrEdit = serializeContext->GetEditContext()) { diff --git a/Code/Tools/SerializeContextTools/SliceConverter.cpp b/Code/Tools/SerializeContextTools/SliceConverter.cpp index 2df3888607..7631eabf22 100644 --- a/Code/Tools/SerializeContextTools/SliceConverter.cpp +++ b/Code/Tools/SerializeContextTools/SliceConverter.cpp @@ -143,7 +143,7 @@ namespace AZ if (packOpened) { [[maybe_unused]] bool closeResult = archiveInterface->ClosePack(filePath); - AZ_Warning("Convert-Slice", !closeResult, "Failed to close '%s'.", filePath.c_str()); + AZ_Warning("Convert-Slice", closeResult, "Failed to close '%s'.", filePath.c_str()); } AZ_Printf("Convert-Slice", "Finished converting '%s' to '%s'\n", filePath.c_str(), outputPath.c_str()); @@ -166,14 +166,16 @@ namespace AZ } // Get all of the entities from the slice. - SliceComponent::EntityList sliceEntities; - bool getEntitiesResult = sliceComponent->GetEntities(sliceEntities); - if ((!getEntitiesResult) || (sliceEntities.empty())) + SliceComponent::EntityList sliceEntities = sliceComponent->GetNewEntities(); + if (sliceEntities.empty()) { AZ_Printf("Convert-Slice", " File not converted: Slice entities could not be retrieved.\n"); return false; } + const SliceComponent::SliceList& sliceList = sliceComponent->GetSlices(); + AZ_Warning("Convert-Slice", sliceList.empty(), " Slice depends on other slices, this conversion will lose data.\n"); + // Create the Prefab with the entities from the slice AZStd::unique_ptr sourceInstance( prefabSystemComponent->CreatePrefab(sliceEntities, {}, outputPath));