Fixes up parents for entities that are moved to another Prefab.
This fixes issues with entities that are moved to another Prefab and have a parent that was also moved to the same Prefab. Entities that have their parent moved to another Prefab continue to work as is because a placeholder entity is always left behind. Entities that are moved to another Prefab but have a parent that's still in the original Prefab will currently not work correctly. This will be a addressed in a future commit. Signed-off-by: AMZN-koppersr <82230785+AMZN-koppersr@users.noreply.github.com>
This commit is contained in:
@@ -585,21 +585,24 @@ namespace AzFramework
|
||||
EBUS_EVENT_PTR(m_notificationBus, AZ::TransformNotificationBus, OnParentChanged, oldParent, parentId);
|
||||
m_parentChangedEvent.Signal(oldParent, parentId);
|
||||
|
||||
if (oldParent != parentId) // Don't send removal notification while activating.
|
||||
if (GetEntity() != nullptr)
|
||||
{
|
||||
EBUS_EVENT_ID(oldParent, AZ::TransformNotificationBus, OnChildRemoved, GetEntityId());
|
||||
auto oldParentTransform = AZ::TransformBus::FindFirstHandler(oldParent);
|
||||
if (oldParentTransform)
|
||||
if (oldParent != parentId) // Don't send removal notification while activating.
|
||||
{
|
||||
oldParentTransform->NotifyChildChangedEvent(AZ::ChildChangeType::Removed, GetEntityId());
|
||||
EBUS_EVENT_ID(oldParent, AZ::TransformNotificationBus, OnChildRemoved, GetEntityId());
|
||||
auto oldParentTransform = AZ::TransformBus::FindFirstHandler(oldParent);
|
||||
if (oldParentTransform)
|
||||
{
|
||||
oldParentTransform->NotifyChildChangedEvent(AZ::ChildChangeType::Removed, GetEntityId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EBUS_EVENT_ID(parentId, AZ::TransformNotificationBus, OnChildAdded, GetEntityId());
|
||||
auto newParentTransform = AZ::TransformBus::FindFirstHandler(parentId);
|
||||
if (newParentTransform)
|
||||
{
|
||||
newParentTransform->NotifyChildChangedEvent(AZ::ChildChangeType::Added, GetEntityId());
|
||||
EBUS_EVENT_ID(parentId, AZ::TransformNotificationBus, OnChildAdded, GetEntityId());
|
||||
auto newParentTransform = AZ::TransformBus::FindFirstHandler(parentId);
|
||||
if (newParentTransform)
|
||||
{
|
||||
newParentTransform->NotifyChildChangedEvent(AZ::ChildChangeType::Added, GetEntityId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+63
-106
@@ -16,6 +16,7 @@
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/std/algorithm.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzFramework/Components/TransformComponent.h>
|
||||
#include <AzFramework/Spawnable/Spawnable.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
#include <AzToolsFramework/Prefab/Instance/Instance.h>
|
||||
@@ -52,14 +53,32 @@ namespace AzToolsFramework::Prefab::SpawnableUtils
|
||||
return result;
|
||||
}
|
||||
|
||||
const AZ::Entity* FindEntity(AZ::EntityId entityId, const AzToolsFramework::Prefab::Instance& source)
|
||||
{
|
||||
const AZ::Entity* result = nullptr;
|
||||
source.GetConstEntities(
|
||||
[&result, entityId](const AZ::Entity& entity)
|
||||
{
|
||||
if (entity.GetId() != entityId)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = &entity;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
AZ::Entity* FindEntity(AZ::EntityId entityId, AzFramework::Spawnable& source)
|
||||
{
|
||||
uint32_t index = AzToolsFramework::Prefab::SpawnableUtils::FindEntityIndex(entityId, source);
|
||||
return index != InvalidEntityIndex ? source.GetEntities()[index].get() : nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
AZStd::unique_ptr<AZ::Entity> CloneEntity(AZ::EntityId entityId, T& source)
|
||||
AZStd::unique_ptr<AZ::Entity> CloneEntity(AZ::EntityId entityId, AzToolsFramework::Prefab::Instance& source)
|
||||
{
|
||||
AZ::Entity* target = Internal::FindEntity(entityId, source);
|
||||
AZ_Assert(
|
||||
@@ -74,43 +93,30 @@ namespace AzToolsFramework::Prefab::SpawnableUtils
|
||||
return clone;
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<AZ::Entity> ReplaceEntityWithPlaceholder(AZ::EntityId entityId, AzToolsFramework::Prefab::Instance& source)
|
||||
AZStd::unique_ptr<AZ::Entity> ReplaceEntityWithPlaceholder(
|
||||
AZ::EntityId entityId,
|
||||
[[maybe_unused]] AZStd::string_view sourcePrefabName,
|
||||
AzToolsFramework::Prefab::Instance& source)
|
||||
{
|
||||
auto&& [instance, alias] = source.FindInstanceAndAlias(entityId);
|
||||
AZ_Assert(
|
||||
instance, "SpawnbleUtils were unable to locate entity alias with id %zu in Instance '%s' for replacing.",
|
||||
aznumeric_cast<AZ::u64>(entityId), source.GetTemplateSourcePath().c_str());
|
||||
instance, "SpawnbleUtils were unable to locate entity alias with id %zu in Instance '%.*s' for replacing.",
|
||||
aznumeric_cast<AZ::u64>(entityId), AZ_STRING_ARG(sourcePrefabName));
|
||||
|
||||
EntityOptionalReference entityData = instance->GetEntity(alias);
|
||||
AZ_Assert(
|
||||
entityData.has_value(), "SpawnbleUtils were unable to locate entity '%.*s' in Instance '%s' for replacing.",
|
||||
AZ_STRING_ARG(alias), source.GetTemplateSourcePath().c_str());
|
||||
entityData.has_value(), "SpawnbleUtils were unable to locate entity '%.*s' in Instance '%.*s' for replacing.",
|
||||
AZ_STRING_ARG(alias), AZ_STRING_ARG(sourcePrefabName));
|
||||
// A new entity id can be used for the placeholder as `ReplaceEntity` will swap the entity ids.
|
||||
auto placeholder = AZStd::make_unique<AZ::Entity>(AZ::Entity::MakeId(), entityData->get().GetName());
|
||||
AZStd::unique_ptr<AZ::Entity> result = instance->ReplaceEntity(AZStd::move(placeholder), alias);
|
||||
return result;
|
||||
return instance->ReplaceEntity(AZStd::move(placeholder), alias);
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<AZ::Entity> ReplaceEntityWithPlaceholder(AZ::EntityId entityId, AzFramework::Spawnable& source)
|
||||
{
|
||||
uint32_t index = AzToolsFramework::Prefab::SpawnableUtils::FindEntityIndex(entityId, source);
|
||||
AZ_Assert(
|
||||
index != InvalidEntityIndex, "SpawnbleUtils were unable to locate entity alias with id %zu in Spawnable for replacing.",
|
||||
aznumeric_cast<AZ::u64>(entityId));
|
||||
|
||||
AZStd::unique_ptr<AZ::Entity> original = AZStd::move(source.GetEntities()[index]);
|
||||
AZ_Assert(
|
||||
original, "SpawnbleUtils were unable to locate entity with id %zu in Spawnable for replacing.",
|
||||
aznumeric_cast<AZ::u64>(entityId));
|
||||
|
||||
source.GetEntities()[index] = AZStd::make_unique<AZ::Entity>(original->GetId(), original->GetName());
|
||||
original->SetId(AZ::Entity::MakeId());
|
||||
return original;
|
||||
}
|
||||
|
||||
template<typename Source>
|
||||
AZStd::pair<AZStd::unique_ptr<AZ::Entity>, AzFramework::Spawnable::EntityAliasType> ApplyAlias(
|
||||
Source& source, AZ::EntityId entityId, AzToolsFramework::Prefab::PrefabConversionUtils::EntityAliasType aliasType)
|
||||
AZStd::string_view sourcePrefabName,
|
||||
AzToolsFramework::Prefab::Instance& source,
|
||||
AZ::EntityId entityId,
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::EntityAliasType aliasType)
|
||||
{
|
||||
namespace PCU = AzToolsFramework::Prefab::PrefabConversionUtils;
|
||||
using ResultPair = AZStd::pair<AZStd::unique_ptr<AZ::Entity>, AzFramework::Spawnable::EntityAliasType>;
|
||||
@@ -123,11 +129,13 @@ namespace AzToolsFramework::Prefab::SpawnableUtils
|
||||
case PCU::EntityAliasType::OptionalReplace:
|
||||
return ResultPair(CloneEntity(entityId, source), AzFramework::Spawnable::EntityAliasType::Replace);
|
||||
case PCU::EntityAliasType::Replace:
|
||||
return ResultPair(ReplaceEntityWithPlaceholder(entityId, source), AzFramework::Spawnable::EntityAliasType::Replace);
|
||||
return ResultPair(
|
||||
ReplaceEntityWithPlaceholder(entityId, sourcePrefabName, source),
|
||||
AzFramework::Spawnable::EntityAliasType::Replace);
|
||||
case PCU::EntityAliasType::Additional:
|
||||
ResultPair(AZStd::make_unique<AZ::Entity>(), AzFramework::Spawnable::EntityAliasType::Additional);
|
||||
return ResultPair(AZStd::make_unique<AZ::Entity>(), AzFramework::Spawnable::EntityAliasType::Additional);
|
||||
case PCU::EntityAliasType::Merge:
|
||||
ResultPair(AZStd::make_unique<AZ::Entity>(), AzFramework::Spawnable::EntityAliasType::Merge);
|
||||
return ResultPair(AZStd::make_unique<AZ::Entity>(), AzFramework::Spawnable::EntityAliasType::Merge);
|
||||
default:
|
||||
AZ_Assert(
|
||||
false, "Invalid PrefabProcessorContext::EntityAliasType type (%i) provided.", aznumeric_cast<uint64_t>(aliasType));
|
||||
@@ -183,7 +191,8 @@ namespace AzToolsFramework::Prefab::SpawnableUtils
|
||||
AliasPath alias = source.GetAliasPathRelativeToInstance(entityId);
|
||||
if (!alias.empty())
|
||||
{
|
||||
auto&& [replacement, storedAliasType] = Internal::ApplyAlias(source, entityId, aliasType);
|
||||
auto&& [replacement, storedAliasType] =
|
||||
Internal::ApplyAlias(sourcePrefabName, source, entityId, aliasType);
|
||||
if (replacement)
|
||||
{
|
||||
AZ::Entity* result = replacement.get();
|
||||
@@ -213,82 +222,30 @@ namespace AzToolsFramework::Prefab::SpawnableUtils
|
||||
}
|
||||
}
|
||||
|
||||
AZ::Entity* CreateEntityAlias(
|
||||
AZStd::string sourcePrefabName,
|
||||
AzToolsFramework::Prefab::Instance& source,
|
||||
AzFramework::Spawnable& target,
|
||||
AZ::EntityId entityId,
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::EntityAliasType aliasType,
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::EntityAliasSpawnableLoadBehavior loadBehavior,
|
||||
uint32_t tag,
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessorContext& context)
|
||||
void PatchParents(const AzToolsFramework::Prefab::Instance& source, AzToolsFramework::Prefab::Instance& target)
|
||||
{
|
||||
using namespace AzToolsFramework::Prefab::PrefabConversionUtils;
|
||||
|
||||
AliasPath alias = source.GetAliasPathRelativeToInstance(entityId);
|
||||
if (!alias.empty())
|
||||
{
|
||||
auto&& [replacement, storedAliasType] = Internal::ApplyAlias(source, entityId, aliasType);
|
||||
if (replacement)
|
||||
target.GetEntities(
|
||||
[&source, &target](AZStd::unique_ptr<AZ::Entity>& entity)
|
||||
{
|
||||
AZ::Entity* result = replacement.get();
|
||||
target.GetEntities().push_back(AZStd::move(replacement));
|
||||
|
||||
EntityAliasStore store;
|
||||
store.m_aliasType = storedAliasType;
|
||||
store.m_source.emplace<EntityAliasPrefabLink>(AZStd::move(sourcePrefabName), AZStd::move(alias));
|
||||
store.m_target.emplace<EntityAliasSpawnableLink>(target, result->GetId());
|
||||
store.m_tag = tag;
|
||||
store.m_loadBehavior = loadBehavior;
|
||||
context.RegisterSpawnableEntityAlias(AZStd::move(store));
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(false, "A replacement for entity with id %zu could not be created.", static_cast<AZ::u64>(entityId));
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(false, "Entity with id %llu was not found in the source prefab.", static_cast<AZ::u64>(entityId));
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
AZ::Entity* CreateEntityAlias(
|
||||
AzFramework::Spawnable& source,
|
||||
AzFramework::Spawnable& target,
|
||||
AZ::EntityId entityId,
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::EntityAliasType aliasType,
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::EntityAliasSpawnableLoadBehavior loadBehavior,
|
||||
uint32_t tag,
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessorContext& context)
|
||||
{
|
||||
using namespace AzToolsFramework::Prefab::PrefabConversionUtils;
|
||||
|
||||
auto&& [replacement, storedAliasType] = Internal::ApplyAlias(source, entityId, aliasType);
|
||||
if (replacement)
|
||||
{
|
||||
AZ::Entity* result = replacement.get();
|
||||
target.GetEntities().push_back(AZStd::move(replacement));
|
||||
|
||||
EntityAliasStore store;
|
||||
store.m_aliasType = storedAliasType;
|
||||
store.m_source.emplace<EntityAliasSpawnableLink>(source, entityId);
|
||||
store.m_target.emplace<EntityAliasSpawnableLink>(target, result->GetId());
|
||||
store.m_tag = tag;
|
||||
store.m_loadBehavior = loadBehavior;
|
||||
context.RegisterSpawnableEntityAlias(AZStd::move(store));
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(false, "A replacement for entity with id %zu could not be created.", static_cast<AZ::u64>(entityId));
|
||||
return nullptr;
|
||||
}
|
||||
AzFramework::TransformComponent* transform = entity->FindComponent<AzFramework::TransformComponent>();
|
||||
if (transform)
|
||||
{
|
||||
if (transform->GetParentId().IsValid())
|
||||
{
|
||||
AliasPath originalParentAlias = source.GetAliasPathRelativeToInstance(transform->GetParentId());
|
||||
if (!originalParentAlias.empty())
|
||||
{
|
||||
AZ::EntityId targetParentId = target.GetEntityIdFromAliasPath(originalParentAlias);
|
||||
if (targetParentId.IsValid())
|
||||
{
|
||||
// If this is valid then the parent was moved to the target spawnable so adjust the entity id.
|
||||
transform->SetParent(targetParentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
uint32_t FindEntityIndex(AZ::EntityId entity, const AzFramework::Spawnable& spawnable)
|
||||
|
||||
@@ -41,23 +41,7 @@ namespace AzToolsFramework::Prefab::SpawnableUtils
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::EntityAliasSpawnableLoadBehavior loadBehavior,
|
||||
uint32_t tag,
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessorContext& context);
|
||||
AZ::Entity* CreateEntityAlias(
|
||||
AZStd::string sourcePrefabName,
|
||||
AzToolsFramework::Prefab::Instance& source,
|
||||
AzFramework::Spawnable& target,
|
||||
AZ::EntityId entityId,
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::EntityAliasType aliasType,
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::EntityAliasSpawnableLoadBehavior loadBehavior,
|
||||
uint32_t tag,
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessorContext& context);
|
||||
AZ::Entity* CreateEntityAlias(
|
||||
AzFramework::Spawnable& source,
|
||||
AzFramework::Spawnable& target,
|
||||
AZ::EntityId entityId,
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::EntityAliasType aliasType,
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::EntityAliasSpawnableLoadBehavior loadBehavior,
|
||||
uint32_t tag,
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessorContext& context);
|
||||
void PatchParents(const AzToolsFramework::Prefab::Instance& source, AzToolsFramework::Prefab::Instance& target);
|
||||
|
||||
uint32_t FindEntityIndex(AZ::EntityId entity, const AzFramework::Spawnable& spawnable);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user