Merge pull request #260 from aws-lumberyard-dev/Prefab/CreatePrefab

Added undo and redo support for nested prefab creation
This commit is contained in:
srikappa-amzn
2021-04-22 17:51:01 -07:00
committed by GitHub
7 changed files with 54 additions and 49 deletions
@@ -279,7 +279,7 @@ namespace AzToolsFramework
AZ::IO::PathView filePath, Prefab::InstanceOptionalReference instanceToParentUnder)
{
AZStd::unique_ptr<Prefab::Instance> createdPrefabInstance =
m_prefabSystemComponent->CreatePrefab(entities, AZStd::move(nestedPrefabInstances), filePath);
m_prefabSystemComponent->CreatePrefab(entities, AZStd::move(nestedPrefabInstances), filePath, nullptr, false);
if (createdPrefabInstance)
{
@@ -321,7 +321,6 @@ namespace AzToolsFramework
removedNestedInstance = AZStd::move(nestedInstanceIterator->second);
removedNestedInstance->m_parent = nullptr;
removedNestedInstance->m_alias = InstanceAlias();
m_nestedInstances.erase(instanceAlias);
}
@@ -396,6 +395,14 @@ namespace AzToolsFramework
}
}
void Instance::GetNestedInstances(const AZStd::function<void(AZStd::unique_ptr<Instance>&)>& callback)
{
for (auto& [instanceAlias, instance] : m_nestedInstances)
{
callback(instance);
}
}
void Instance::GetEntities(const AZStd::function<bool(AZStd::unique_ptr<AZ::Entity>&)>& callback)
{
for (auto& [entityAlias, entity] : m_entities)
@@ -114,6 +114,7 @@ namespace AzToolsFramework
void GetConstEntities(const AZStd::function<bool(const AZ::Entity&)>& callback);
void GetNestedEntities(const AZStd::function<bool(AZStd::unique_ptr<AZ::Entity>&)>& callback);
void GetEntities(const AZStd::function<bool(AZStd::unique_ptr<AZ::Entity>&)>& callback);
void GetNestedInstances(const AZStd::function<void(AZStd::unique_ptr<Instance>&)>& callback);
/**
* Gets the alias for a given EnitityId in the Instance DOM.
@@ -101,6 +101,10 @@ namespace AzToolsFramework
nestedInstance->GetInstanceAlias(), nestedInstance->GetLinkId(), undoBatch.GetUndoBatch());
}
PrefabUndoHelpers::UpdatePrefabInstance(
commonRootEntityOwningInstance->get(), "Update prefab instance", commonRootInstanceDomBeforeCreate,
undoBatch.GetUndoBatch());
auto prefabEditorEntityOwnershipInterface = AZ::Interface<PrefabEditorEntityOwnershipInterface>::Get();
if (!prefabEditorEntityOwnershipInterface)
{
@@ -118,13 +122,21 @@ namespace AzToolsFramework
"(A null instance is returned)."));
}
PrefabUndoHelpers::UpdatePrefabInstance(
commonRootEntityOwningInstance->get(), "Update prefab instance", commonRootInstanceDomBeforeCreate, undoBatch.GetUndoBatch());
AZ::EntityId containerEntityId = instanceToCreate->get().GetContainerEntityId();
instanceToCreate->get().GetNestedInstances([&](AZStd::unique_ptr<Instance>& nestedInstance) {
AZ_Assert(nestedInstance, "Invalid nested instance found in the new prefab created.");
EntityOptionalReference nestedInstanceContainerEntity = nestedInstance->GetContainerEntity();
AZ_Assert(
nestedInstanceContainerEntity, "Invalid container entity found for the nested instance used in prefab creation.");
CreateLink(
{&nestedInstanceContainerEntity->get()}, *nestedInstance, instanceToCreate->get().GetTemplateId(),
undoBatch.GetUndoBatch(), containerEntityId);
});
CreateLink(
topLevelEntities, instanceToCreate->get(), commonRootEntityOwningInstance->get().GetTemplateId(), undoBatch.GetUndoBatch(),
commonRootEntityId);
AZ::EntityId containerEntityId = instanceToCreate->get().GetContainerEntityId();
// Change top level entities to be parented to the container entity
// Mark them as dirty so this change is correctly applied to the template
@@ -225,19 +237,7 @@ namespace AzToolsFramework
PrefabOperationResult PrefabPublicHandler::SavePrefab(AZ::IO::Path filePath)
{
auto prefabSystemComponentInterface = AZ::Interface<PrefabSystemComponentInterface>::Get();
if (!prefabSystemComponentInterface)
{
AZ_Assert(
false,
"Prefab - PrefabPublicHandler - "
"Prefab System Component Interface could not be found. "
"Check that it is being correctly initialized.");
return AZ::Failure(
AZStd::string("SavePrefab - Internal error (Prefab System Component Interface could not be found)."));
}
auto templateId = prefabSystemComponentInterface->GetTemplateIdFromFilePath(filePath.c_str());
auto templateId = m_prefabSystemComponentInterface->GetTemplateIdFromFilePath(filePath.c_str());
if (templateId == InvalidTemplateId)
{
@@ -438,26 +438,14 @@ namespace AzToolsFramework
PrefabRequestResult PrefabPublicHandler::HasUnsavedChanges(AZ::IO::Path prefabFilePath) const
{
auto prefabSystemComponentInterface = AZ::Interface<PrefabSystemComponentInterface>::Get();
if (!prefabSystemComponentInterface)
{
AZ_Assert(
false,
"Prefab - PrefabPublicHandler - "
"Prefab System Component Interface could not be found. "
"Check that it is being correctly initialized.");
return AZ::Failure(
AZStd::string("HasUnsavedChanges - Internal error (Prefab System Component Interface could not be found)."));
}
auto templateId = prefabSystemComponentInterface->GetTemplateIdFromFilePath(prefabFilePath.c_str());
auto templateId = m_prefabSystemComponentInterface->GetTemplateIdFromFilePath(prefabFilePath.c_str());
if (templateId == InvalidTemplateId)
{
return AZ::Failure(AZStd::string("HasUnsavedChanges - Path error. Path could be invalid, or the prefab may not be loaded in this level."));
}
return AZ::Success(prefabSystemComponentInterface->IsTemplateDirty(templateId));
return AZ::Success(m_prefabSystemComponentInterface->IsTemplateDirty(templateId));
}
PrefabOperationResult PrefabPublicHandler::DeleteEntitiesInInstance(const EntityIdList& entityIds)
@@ -91,8 +91,9 @@ namespace AzToolsFramework
m_instanceUpdateExecutor.UpdateTemplateInstancesInQueue();
}
AZStd::unique_ptr<Instance> PrefabSystemComponent::CreatePrefab(const AZStd::vector<AZ::Entity*>& entities, AZStd::vector<AZStd::unique_ptr<Instance>>&& instancesToConsume,
AZ::IO::PathView filePath, AZStd::unique_ptr<AZ::Entity> containerEntity)
AZStd::unique_ptr<Instance> PrefabSystemComponent::CreatePrefab(
const AZStd::vector<AZ::Entity*>& entities, AZStd::vector<AZStd::unique_ptr<Instance>>&& instancesToConsume,
AZ::IO::PathView filePath, AZStd::unique_ptr<AZ::Entity> containerEntity, bool shouldCreateLinks)
{
AZ::IO::Path relativeFilePath = m_prefabLoader.GetRelativePathToProject(filePath);
if (GetTemplateIdFromFilePath(relativeFilePath) != InvalidTemplateId)
@@ -123,7 +124,7 @@ namespace AzToolsFramework
newInstance->SetTemplateSourcePath(relativeFilePath);
newInstance->SetContainerEntityName(relativeFilePath.Stem().Native());
TemplateId newTemplateId = CreateTemplateFromInstance(*newInstance);
TemplateId newTemplateId = CreateTemplateFromInstance(*newInstance, shouldCreateLinks);
if (newTemplateId == InvalidTemplateId)
{
AZ_Error("Prefab", false,
@@ -289,7 +290,7 @@ namespace AzToolsFramework
return newInstance;
}
TemplateId PrefabSystemComponent::CreateTemplateFromInstance(Instance& instance)
TemplateId PrefabSystemComponent::CreateTemplateFromInstance(Instance& instance, bool shouldCreateLinks)
{
// We will register the template to match the path the instance has
const AZ::IO::Path& templateSourcePath = instance.GetTemplateSourcePath();
@@ -323,14 +324,15 @@ namespace AzToolsFramework
return InvalidTemplateId;
}
if (!GenerateLinksForNewTemplate(newTemplateId, instance))
if (shouldCreateLinks)
{
// Clear new template and any links associated with it
RemoveTemplate(newTemplateId);
return InvalidTemplateId;
if (!GenerateLinksForNewTemplate(newTemplateId, instance))
{
// Clear new template and any links associated with it
RemoveTemplate(newTemplateId);
return InvalidTemplateId;
}
}
return newTemplateId;
}
@@ -187,17 +187,22 @@ namespace AzToolsFramework
* @param entities A vector of entities that will be used in the new instance. May be empty
* @param instances A vector of Prefab Instances that will be nested in the new instance, will be consumed and moved.
* May be empty
* @param filePath the path to associate the template of the new instance to
* @param filePath the path to associate the template of the new instance to.
* @param containerEntity The container entity for the prefab to be created. It will be created if a nullptr is provided.
* @param shouldCreateLinks The flag indicating if links should be created between the templates of the instance
* and its nested instances.
* @return A pointer to the newly created instance. nullptr on failure
*/
AZStd::unique_ptr<Instance> CreatePrefab(const AZStd::vector<AZ::Entity*>& entities, AZStd::vector<AZStd::unique_ptr<Instance>>&& instancesToConsume,
AZ::IO::PathView filePath, AZStd::unique_ptr<AZ::Entity> containerEntity = nullptr) override;
AZStd::unique_ptr<Instance> CreatePrefab(
const AZStd::vector<AZ::Entity*>& entities, AZStd::vector<AZStd::unique_ptr<Instance>>&& instancesToConsume,
AZ::IO::PathView filePath, AZStd::unique_ptr<AZ::Entity> containerEntity = nullptr,
bool ShouldCreateLinks = true) override;
PrefabDom& FindTemplateDom(TemplateId templateId) override;
/**
* Updates a template with the given updated DOM.
*
*
* @param templateId The id of the template to update.
* @param updatedDom The DOM to update the template with.
*/
@@ -260,9 +265,11 @@ namespace AzToolsFramework
/**
* Takes a prefab instance and generates a new Prefab Template
* along with any new Prefab Links representing any of the nested instances present
* @param instance The instance used to generate the new Template
* @param instance The instance used to generate the new Template.
* @param shouldCreateLinks The flag indicating if links should be created between the templates of the instance
* and its nested instances.
*/
TemplateId CreateTemplateFromInstance(Instance& instance);
TemplateId CreateTemplateFromInstance(Instance& instance, bool shouldCreateLinks);
/**
* Connect two templates with given link, and a nested instance value iterator
@@ -61,7 +61,7 @@ namespace AzToolsFramework
virtual AZStd::unique_ptr<Instance> InstantiatePrefab(const TemplateId& templateId) = 0;
virtual AZStd::unique_ptr<Instance> CreatePrefab(const AZStd::vector<AZ::Entity*>& entities,
AZStd::vector<AZStd::unique_ptr<Instance>>&& instancesToConsume, AZ::IO::PathView filePath,
AZStd::unique_ptr<AZ::Entity> containerEntity = nullptr) = 0;
AZStd::unique_ptr<AZ::Entity> containerEntity = nullptr, bool ShouldCreateLinks = true) = 0;
};