Merge branch 'main' into Prefab/CreatePrefab
This commit is contained in:
+66
-1
@@ -13,6 +13,7 @@
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/Script/ScriptSystemBus.h>
|
||||
#include <AzCore/Serialization/Utils.h>
|
||||
#include <AzFramework/API/ApplicationAPI.h>
|
||||
#include <AzFramework/Entity/GameEntityContextBus.h>
|
||||
#include <AzFramework/Spawnable/RootSpawnableInterface.h>
|
||||
@@ -334,6 +335,65 @@ namespace AzToolsFramework
|
||||
m_validateEntitiesCallback = AZStd::move(validateEntitiesCallback);
|
||||
}
|
||||
|
||||
void PrefabEditorEntityOwnershipService::LoadReferencedAssets(AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& referencedAssets)
|
||||
{
|
||||
// Start our loads on all assets by calling GetAsset from the AssetManager
|
||||
for (AZ::Data::Asset<AZ::Data::AssetData>& asset : referencedAssets)
|
||||
{
|
||||
if (!asset.GetId().IsValid())
|
||||
{
|
||||
AZ_Error("Prefab", false, "Invalid asset found referenced in scene while entering game mode");
|
||||
continue;
|
||||
}
|
||||
|
||||
const AZ::Data::AssetLoadBehavior loadBehavior = asset.GetAutoLoadBehavior();
|
||||
|
||||
if (loadBehavior == AZ::Data::AssetLoadBehavior::NoLoad)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
AZ::Data::AssetId assetId = asset.GetId();
|
||||
AZ::Data::AssetType assetType = asset.GetType();
|
||||
|
||||
asset = AZ::Data::AssetManager::Instance().GetAsset(assetId, assetType, loadBehavior);
|
||||
|
||||
if (!asset.GetId().IsValid())
|
||||
{
|
||||
AZ_Error("Prefab", false, "Invalid asset found referenced in scene while entering game mode");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// For all Preload assets we block until they're ready
|
||||
// We do this as a seperate pass so that we don't interrupt queuing up all other asset loads
|
||||
for (AZ::Data::Asset<AZ::Data::AssetData>& asset : referencedAssets)
|
||||
{
|
||||
if (!asset.GetId().IsValid())
|
||||
{
|
||||
AZ_Error("Prefab", false, "Invalid asset found referenced in scene while entering game mode");
|
||||
continue;
|
||||
}
|
||||
|
||||
const AZ::Data::AssetLoadBehavior loadBehavior = asset.GetAutoLoadBehavior();
|
||||
|
||||
if (loadBehavior != AZ::Data::AssetLoadBehavior::PreLoad)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
asset.BlockUntilLoadComplete();
|
||||
|
||||
if (asset.IsError())
|
||||
{
|
||||
AZ_Error("Prefab", false, "Asset with id %s failed to preload while entering game mode",
|
||||
asset.GetId().ToString<AZStd::string>().c_str());
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PrefabEditorEntityOwnershipService::StartPlayInEditor()
|
||||
{
|
||||
// This is a workaround until the replacement for GameEntityContext is done
|
||||
@@ -373,16 +433,21 @@ namespace AzToolsFramework
|
||||
rootSpawnableIndex = m_playInEditorData.m_assets.size();
|
||||
}
|
||||
|
||||
LoadReferencedAssets(product.GetReferencedAssets());
|
||||
|
||||
AZ::Data::AssetInfo info;
|
||||
info.m_assetId = product.GetAsset().GetId();
|
||||
info.m_assetType = product.GetAssetType();
|
||||
info.m_relativePath = product.GetId();
|
||||
|
||||
AZ::Data::AssetCatalogRequestBus::Broadcast(
|
||||
&AZ::Data::AssetCatalogRequestBus::Events::RegisterAsset, product.GetAsset().GetId(), info);
|
||||
&AZ::Data::AssetCatalogRequestBus::Events::RegisterAsset, info.m_assetId, info);
|
||||
m_playInEditorData.m_assets.emplace_back(product.ReleaseAsset().release(), AZ::Data::AssetLoadBehavior::Default);
|
||||
}
|
||||
|
||||
// make sure that PRE_NOTIFY assets get their notify before we activate, so that we can preserve the order of
|
||||
// (load asset) -> (notify) -> (init) -> (activate)
|
||||
AZ::Data::AssetManager::Instance().DispatchEvents();
|
||||
|
||||
if (rootSpawnableIndex != NoRootSpawnable)
|
||||
{
|
||||
|
||||
+2
@@ -199,6 +199,8 @@ namespace AzToolsFramework
|
||||
|
||||
void OnEntityRemoved(AZ::EntityId entityId);
|
||||
|
||||
void LoadReferencedAssets(AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& referencedAssets);
|
||||
|
||||
OnEntitiesAddedCallback m_entitiesAddedCallback;
|
||||
OnEntitiesRemovedCallback m_entitiesRemovedCallback;
|
||||
ValidateEntitiesCallback m_validateEntitiesCallback;
|
||||
|
||||
@@ -11,8 +11,10 @@
|
||||
*/
|
||||
|
||||
#include <AzCore/Asset/AssetManager.h>
|
||||
#include <AzCore/Asset/AssetJsonSerializer.h>
|
||||
#include <AzCore/JSON/prettywriter.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerialization.h>
|
||||
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabDomUtils.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/Instance.h>
|
||||
@@ -115,6 +117,48 @@ namespace AzToolsFramework
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadInstanceFromPrefabDom(
|
||||
Instance& instance, const PrefabDom& prefabDom, AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& referencedAssets, LoadInstanceFlags flags)
|
||||
{
|
||||
// When entities are rebuilt they are first destroyed. As a result any assets they were exclusively holding on to will
|
||||
// be released and reloaded once the entities are built up again. By suspending asset release temporarily the asset reload
|
||||
// is avoided.
|
||||
AZ::Data::AssetManager::Instance().SuspendAssetRelease();
|
||||
|
||||
InstanceEntityIdMapper entityIdMapper;
|
||||
entityIdMapper.SetLoadingInstance(instance);
|
||||
if ((flags & LoadInstanceFlags::AssignRandomEntityId) == LoadInstanceFlags::AssignRandomEntityId)
|
||||
{
|
||||
entityIdMapper.SetEntityIdGenerationApproach(InstanceEntityIdMapper::EntityIdGenerationApproach::Random);
|
||||
}
|
||||
|
||||
AZ::JsonDeserializerSettings settings;
|
||||
// The InstanceEntityIdMapper is registered twice because it's used in several places during deserialization where one is
|
||||
// specific for the InstanceEntityIdMapper and once for the generic JsonEntityIdMapper. Because the Json Serializer's meta
|
||||
// data has strict typing and doesn't look for inheritance both have to be explicitly added so they're found both locations.
|
||||
settings.m_metadata.Add(static_cast<AZ::JsonEntityIdSerializer::JsonEntityIdMapper*>(&entityIdMapper));
|
||||
settings.m_metadata.Add(&entityIdMapper);
|
||||
settings.m_metadata.Create<AZ::Data::SerializedAssetTracker>();
|
||||
|
||||
AZ::JsonSerializationResult::ResultCode result =
|
||||
AZ::JsonSerialization::Load(instance, prefabDom, settings);
|
||||
|
||||
AZ::Data::AssetManager::Instance().ResumeAssetRelease();
|
||||
|
||||
if (result.GetProcessing() == AZ::JsonSerializationResult::Processing::Halted)
|
||||
{
|
||||
AZ_Error("Prefab", false,
|
||||
"Failed to de-serialize Prefab Instance from Prefab DOM. "
|
||||
"Unable to proceed.");
|
||||
|
||||
return false;
|
||||
}
|
||||
AZ::Data::SerializedAssetTracker* assetTracker = settings.m_metadata.Find<AZ::Data::SerializedAssetTracker>();
|
||||
|
||||
referencedAssets = AZStd::move(assetTracker->GetTrackedAssets());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadInstanceFromPrefabDom(
|
||||
Instance& instance, Instance::EntityList& newlyAddedEntities, const PrefabDom& prefabDom, LoadInstanceFlags flags)
|
||||
{
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/optional.h>
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/Instance.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabDomTypes.h>
|
||||
|
||||
@@ -42,7 +43,7 @@ namespace AzToolsFramework
|
||||
/**
|
||||
* Stores a valid Prefab Instance within a Prefab Dom. Useful for generating Templates
|
||||
* @param instance The instance to store
|
||||
* @param prefabDom the prefabDom that will be used to store the Instance data
|
||||
* @param prefabDom The prefabDom that will be used to store the Instance data
|
||||
* @return bool on whether the operation succeeded
|
||||
*/
|
||||
bool StoreInstanceInPrefabDom(const Instance& instance, PrefabDom& prefabDom);
|
||||
@@ -60,20 +61,32 @@ namespace AzToolsFramework
|
||||
/**
|
||||
* Loads a valid Prefab Instance from a Prefab Dom. Useful for generating Instances.
|
||||
* @param instance The Instance to load.
|
||||
* @param prefabDom the prefabDom that will be used to load the Instance data.
|
||||
* @param shouldClearContainers whether to clear containers in Instance while loading.
|
||||
* @param prefabDom The prefabDom that will be used to load the Instance data.
|
||||
* @param shouldClearContainers Whether to clear containers in Instance while loading.
|
||||
* @return bool on whether the operation succeeded.
|
||||
*/
|
||||
bool LoadInstanceFromPrefabDom(
|
||||
Instance& instance, const PrefabDom& prefabDom, LoadInstanceFlags flags = LoadInstanceFlags::None);
|
||||
|
||||
/**
|
||||
* Loads a valid Prefab Instance from a Prefab Dom. Useful for generating Instances.
|
||||
* @param instance The Instance to load.
|
||||
* @param referencedAssets AZ::Assets discovered during json load are added to this list
|
||||
* @param prefabDom The prefabDom that will be used to load the Instance data.
|
||||
* @param shouldClearContainers Whether to clear containers in Instance while loading.
|
||||
* @return bool on whether the operation succeeded.
|
||||
*/
|
||||
bool LoadInstanceFromPrefabDom(
|
||||
Instance& instance, const PrefabDom& prefabDom, AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& referencedAssets,
|
||||
LoadInstanceFlags flags = LoadInstanceFlags::None);
|
||||
|
||||
/**
|
||||
* Loads a valid Prefab Instance from a Prefab Dom. Useful for generating Instances.
|
||||
* @param instance The Instance to load.
|
||||
* @param newlyAddedEntities The new instances added during deserializing the instance. These are the entities found
|
||||
* in the prefabDom.
|
||||
* @param prefabDom the prefabDom that will be used to load the Instance data.
|
||||
* @param shouldClearContainers whether to clear containers in Instance while loading.
|
||||
* @param prefabDom The prefabDom that will be used to load the Instance data.
|
||||
* @param shouldClearContainers Whether to clear containers in Instance while loading.
|
||||
* @return bool on whether the operation succeeded.
|
||||
*/
|
||||
bool LoadInstanceFromPrefabDom(
|
||||
|
||||
@@ -89,7 +89,7 @@ namespace AzToolsFramework
|
||||
if (!RetrieveAndSortPrefabEntitiesAndInstances(inputEntityList, commonRootEntityOwningInstance->get(), entities, instances))
|
||||
{
|
||||
return AZ::Failure(
|
||||
AZStd::string("Could not create a new prefab out of the entities provided - entities do not share a common root."));
|
||||
AZStd::string("Could not create a new prefab out of the entities provided - invalid selection."));
|
||||
}
|
||||
|
||||
// When we create a prefab with other prefab instances, we have to remove the existing links between the source and
|
||||
@@ -155,12 +155,16 @@ namespace AzToolsFramework
|
||||
|
||||
for (AZ::Entity* topLevelEntity : topLevelEntities)
|
||||
{
|
||||
m_prefabUndoCache.UpdateCache(topLevelEntity->GetId());
|
||||
AZ::EntityId topLevelEntityId = topLevelEntity->GetId();
|
||||
if (topLevelEntityId.IsValid())
|
||||
{
|
||||
m_prefabUndoCache.UpdateCache(topLevelEntity->GetId());
|
||||
|
||||
// Parenting entities would mark entities as dirty. But we want to unmark the top level entities as dirty because
|
||||
// if we don't, the template created would be updated and cause issues with undo operation followed by instantiation.
|
||||
ToolsApplicationRequests::Bus::Broadcast(
|
||||
&ToolsApplicationRequests::Bus::Events::RemoveDirtyEntity, topLevelEntity->GetId());
|
||||
// Parenting entities would mark entities as dirty. But we want to unmark the top level entities as dirty because
|
||||
// if we don't, the template created would be updated and cause issues with undo operation followed by instantiation.
|
||||
ToolsApplicationRequests::Bus::Broadcast(
|
||||
&ToolsApplicationRequests::Bus::Events::RemoveDirtyEntity, topLevelEntity->GetId());
|
||||
}
|
||||
}
|
||||
|
||||
// Select Container Entity
|
||||
@@ -255,6 +259,21 @@ namespace AzToolsFramework
|
||||
// Retrieve entityList from entityIds
|
||||
inputEntityList = EntityIdListToEntityList(entityIds);
|
||||
|
||||
// Remove Level Container Entity if it's part of the list
|
||||
AZ::EntityId levelEntityId = GetLevelInstanceContainerEntityId();
|
||||
if (levelEntityId.IsValid())
|
||||
{
|
||||
AZ::Entity* levelEntity = GetEntityById(levelEntityId);
|
||||
if (levelEntity)
|
||||
{
|
||||
auto levelEntityIter = AZStd::find(inputEntityList.begin(), inputEntityList.end(), levelEntity);
|
||||
if (levelEntityIter != inputEntityList.end())
|
||||
{
|
||||
inputEntityList.erase(levelEntityIter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find common root and top level entities
|
||||
bool entitiesHaveCommonRoot = false;
|
||||
|
||||
@@ -835,6 +854,11 @@ namespace AzToolsFramework
|
||||
const EntityList& inputEntities, Instance& commonRootEntityOwningInstance,
|
||||
EntityList& outEntities, AZStd::vector<AZStd::unique_ptr<Instance>>& outInstances) const
|
||||
{
|
||||
if (inputEntities.size() == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AZStd::queue<AZ::Entity*> entityQueue;
|
||||
|
||||
for (auto inputEntity : inputEntities)
|
||||
@@ -922,7 +946,7 @@ namespace AzToolsFramework
|
||||
outInstances.push_back(AZStd::move(commonRootEntityOwningInstance.DetachNestedInstance(instancePtr->GetInstanceAlias())));
|
||||
}
|
||||
|
||||
return true;
|
||||
return (outEntities.size() + outInstances.size()) > 0;
|
||||
}
|
||||
|
||||
bool PrefabPublicHandler::EntitiesBelongToSameInstance(const EntityIdList& entityIds) const
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
AZStd::move(uniqueName), context.GetSourceUuid(), AZStd::move(serializer));
|
||||
AZ_Assert(spawnable, "Failed to create a new spawnable.");
|
||||
|
||||
bool result = SpawnableUtils::CreateSpawnable(*spawnable, prefab);
|
||||
bool result = SpawnableUtils::CreateSpawnable(*spawnable, prefab, object.GetReferencedAssets());
|
||||
if (result)
|
||||
{
|
||||
AzFramework::Spawnable::EntityList& entities = spawnable->GetEntities();
|
||||
|
||||
+10
@@ -56,6 +56,16 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
return *m_asset;
|
||||
}
|
||||
|
||||
AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& ProcessedObjectStore::GetReferencedAssets()
|
||||
{
|
||||
return m_referencedAssets;
|
||||
}
|
||||
|
||||
const AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& ProcessedObjectStore::GetReferencedAssets() const
|
||||
{
|
||||
return m_referencedAssets;
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<AZ::Data::AssetData> ProcessedObjectStore::ReleaseAsset()
|
||||
{
|
||||
return AZStd::move(m_asset);
|
||||
|
||||
+5
@@ -48,6 +48,10 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
AZ::Data::AssetData& GetAsset();
|
||||
AZStd::unique_ptr<AZ::Data::AssetData> ReleaseAsset();
|
||||
|
||||
AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& GetReferencedAssets();
|
||||
const AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& GetReferencedAssets() const;
|
||||
|
||||
|
||||
const AZStd::string& GetId() const;
|
||||
|
||||
private:
|
||||
@@ -55,6 +59,7 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
|
||||
|
||||
SerializerFunction m_assetSerializer;
|
||||
AZStd::unique_ptr<AZ::Data::AssetData> m_asset;
|
||||
AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>> m_referencedAssets;
|
||||
AZStd::string m_uniqueId;
|
||||
};
|
||||
|
||||
|
||||
+9
-2
@@ -28,16 +28,23 @@ namespace AzToolsFramework::Prefab::SpawnableUtils
|
||||
AzFramework::Spawnable CreateSpawnable(const PrefabDom& prefabDom)
|
||||
{
|
||||
AzFramework::Spawnable spawnable;
|
||||
[[maybe_unused]] bool result = CreateSpawnable(spawnable, prefabDom);
|
||||
AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>> referencedAssets;
|
||||
[[maybe_unused]] bool result = CreateSpawnable(spawnable, prefabDom, referencedAssets);
|
||||
AZ_Assert(result,
|
||||
"Failed to Load Prefab Instance from given Prefab DOM while Spawnable creation.");
|
||||
return spawnable;
|
||||
}
|
||||
|
||||
bool CreateSpawnable(AzFramework::Spawnable& spawnable, const PrefabDom& prefabDom)
|
||||
{
|
||||
AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>> referencedAssets;
|
||||
return CreateSpawnable(spawnable, prefabDom, referencedAssets);
|
||||
}
|
||||
|
||||
bool CreateSpawnable(AzFramework::Spawnable& spawnable, const PrefabDom& prefabDom, AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& referencedAssets)
|
||||
{
|
||||
Instance instance;
|
||||
if (Prefab::PrefabDomUtils::LoadInstanceFromPrefabDom(instance, prefabDom,
|
||||
if (Prefab::PrefabDomUtils::LoadInstanceFromPrefabDom(instance, prefabDom, referencedAssets,
|
||||
Prefab::PrefabDomUtils::LoadInstanceFlags::AssignRandomEntityId)) // Always assign random entity ids because the spawnable is
|
||||
// going to be used to create clones of the entities.
|
||||
{
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace AzToolsFramework::Prefab::SpawnableUtils
|
||||
{
|
||||
AzFramework::Spawnable CreateSpawnable(const PrefabDom& prefabDom);
|
||||
bool CreateSpawnable(AzFramework::Spawnable& spawnable, const PrefabDom& prefabDom);
|
||||
bool CreateSpawnable(AzFramework::Spawnable& spawnable, const PrefabDom& prefabDom, AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& referencedAssets);
|
||||
|
||||
void SortEntitiesByTransformHierarchy(AzFramework::Spawnable& spawnable);
|
||||
} // namespace AzToolsFramework::Prefab::SpawnableUtils
|
||||
|
||||
@@ -1353,7 +1353,7 @@ namespace AzToolsFramework
|
||||
// Iterate over the entities left in the instance and if none of them have this
|
||||
// asset entity as its ancestor, then we want to remove it.
|
||||
// \todo - Investigate ways to make this non-linear time. Tricky since removed entities
|
||||
// obviously aren't maintained in any maps. (https://jira.agscollab.com/browse/LY-88218)
|
||||
// obviously aren't maintained in any maps. (LY-88218)
|
||||
bool foundAsAncestor = false;
|
||||
for (const AZ::Entity* instanceEntity : instanceEntities)
|
||||
{
|
||||
|
||||
+32
-19
@@ -151,32 +151,36 @@ namespace AzToolsFramework
|
||||
{
|
||||
if (!selectedEntities.empty())
|
||||
{
|
||||
bool layerInSelection = false;
|
||||
|
||||
for (AZ::EntityId entityId : selectedEntities)
|
||||
// Hide if the only selected entity is the Level Container
|
||||
if (selectedEntities.size() > 1 || !s_prefabPublicInterface->IsLevelInstanceContainerEntity(selectedEntities[0]))
|
||||
{
|
||||
if (!layerInSelection)
|
||||
{
|
||||
AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult(
|
||||
layerInSelection, entityId,
|
||||
&AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::HasLayer);
|
||||
bool layerInSelection = false;
|
||||
|
||||
if (layerInSelection)
|
||||
for (AZ::EntityId entityId : selectedEntities)
|
||||
{
|
||||
if (!layerInSelection)
|
||||
{
|
||||
break;
|
||||
AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult(
|
||||
layerInSelection, entityId,
|
||||
&AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::HasLayer);
|
||||
|
||||
if (layerInSelection)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Layers can't be in prefabs.
|
||||
if (!layerInSelection)
|
||||
{
|
||||
QAction* createAction = menu->addAction(QObject::tr("Create Prefab..."));
|
||||
createAction->setToolTip(QObject::tr("Creates a prefab out of the currently selected entities."));
|
||||
// Layers can't be in prefabs.
|
||||
if (!layerInSelection)
|
||||
{
|
||||
QAction* createAction = menu->addAction(QObject::tr("Create Prefab..."));
|
||||
createAction->setToolTip(QObject::tr("Creates a prefab out of the currently selected entities."));
|
||||
|
||||
QObject::connect(createAction, &QAction::triggered, createAction, [this, selectedEntities] {
|
||||
ContextMenu_CreatePrefab(selectedEntities);
|
||||
});
|
||||
QObject::connect(createAction, &QAction::triggered, createAction, [this, selectedEntities] {
|
||||
ContextMenu_CreatePrefab(selectedEntities);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -272,6 +276,15 @@ namespace AzToolsFramework
|
||||
QWidget* activeWindow = QApplication::activeWindow();
|
||||
const AZStd::string prefabFilesPath = "@devassets@/Prefabs";
|
||||
|
||||
// Remove Level entity if it's part of the list
|
||||
|
||||
auto levelContainerIter =
|
||||
AZStd::find(selectedEntities.begin(), selectedEntities.end(), s_prefabPublicInterface->GetLevelInstanceContainerEntityId());
|
||||
if (levelContainerIter != selectedEntities.end())
|
||||
{
|
||||
selectedEntities.erase(levelContainerIter);
|
||||
}
|
||||
|
||||
// Set default folder for prefabs
|
||||
AZ::IO::FileIOBase* fileIoBaseInstance = AZ::IO::FileIOBase::GetInstance();
|
||||
|
||||
|
||||
+30
-3
@@ -63,23 +63,40 @@ namespace AzToolsFramework
|
||||
|
||||
void PropertyManagerComponent::Deactivate()
|
||||
{
|
||||
// Delete all remaining auto-delete or built-in handlers.
|
||||
for (auto it = m_builtInHandlers.begin(); it != m_builtInHandlers.end(); ++it)
|
||||
{
|
||||
UnregisterPropertyType(*it);
|
||||
#ifdef AZ_DEBUG_BUILD
|
||||
// For debug builds, we'll take the extra time to delete each handler that we're deleting from m_Handlers.
|
||||
// We loop through m_Handlers below to ensure that we don't have any other handlers still registered after
|
||||
// we've deleted these.
|
||||
AZStd::erase_if(m_Handlers, [it](const auto& item) {
|
||||
auto const& [key, value] = item;
|
||||
return (key == (*it)->GetHandlerName()) && (value == (*it));
|
||||
});
|
||||
#endif
|
||||
|
||||
delete *it;
|
||||
}
|
||||
|
||||
m_builtInHandlers.clear();
|
||||
|
||||
|
||||
#ifdef _DEBUG
|
||||
#ifdef AZ_DEBUG_BUILD
|
||||
// Loop through all the remaining registered handlers (if any) and print out an error, as these all are probably memory
|
||||
// leaks. UnregisterPropertyType should have been called on these already, and their pointers should have been deleted
|
||||
// by the caller.
|
||||
auto it = m_Handlers.begin();
|
||||
while (it != m_Handlers.end())
|
||||
{
|
||||
AZ_Error("PropertyManager", false, "Property Handler 0x%08x is still registered during shutdown", it->first);
|
||||
++it;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
m_Handlers.clear();
|
||||
m_DefaultHandlers.clear();
|
||||
|
||||
PropertyTypeRegistrationMessages::Bus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
@@ -142,6 +159,16 @@ namespace AzToolsFramework
|
||||
}
|
||||
++defaultIt;
|
||||
}
|
||||
|
||||
if (pHandler->AutoDelete())
|
||||
{
|
||||
m_builtInHandlers.erase(AZStd::remove(m_builtInHandlers.begin(), m_builtInHandlers.end(), pHandler),
|
||||
m_builtInHandlers.end());
|
||||
AZ_Assert(false,
|
||||
"Handlers with AutoDelete set should not call UnregisterPropertyType. To fix, do one of the following:\n"
|
||||
" 1. Set AutoDelete to false in the handler, call UnregisterPropertyType, and the caller should delete the handler.\n"
|
||||
" 2. Set AutoDelete to true in the handler and do NOT call UnregisterPropertyType or delete the handler.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -211,6 +211,15 @@ namespace UnitTest
|
||||
EXPECT_EQ(screenPoint, ScreenPoint(45, 170));
|
||||
}
|
||||
|
||||
TEST(ViewportScreen, ScreenVectorLengthReturned)
|
||||
{
|
||||
using AzFramework::ScreenVector;
|
||||
|
||||
EXPECT_NEAR(AzFramework::ScreenVectorLength(ScreenVector(1, 1)), 1.41421f, 0.001f);
|
||||
EXPECT_NEAR(AzFramework::ScreenVectorLength(ScreenVector(3, 4)), 5.0f, 0.001f);
|
||||
EXPECT_NEAR(AzFramework::ScreenVectorLength(ScreenVector(12, 15)), 19.20937f, 0.001f);
|
||||
}
|
||||
|
||||
TEST(ViewportScreen, CanGetCameraTransformFromCameraViewAndBack)
|
||||
{
|
||||
const auto screenDimensions = AZ::Vector2(1024.0f, 768.0f);
|
||||
|
||||
Reference in New Issue
Block a user