Instantiate Prefab

This commit is contained in:
daimini
2021-04-21 17:42:33 -07:00
parent 421a1dbfdb
commit ca8d6f8818
7 changed files with 166 additions and 36 deletions
@@ -31,11 +31,18 @@ namespace AzToolsFramework
//! /param entities The entities to put under the new prefab.
//! /param nestedPrefabInstances The nested prefab instances to put under the new prefab.
//! /param filePath The filepath corresponding to the prefab file to be created.
//! /param instanceToParentUnder The instance under which the newly created prefab instance is parented under.
//! /param instanceToParentUnder The instance the newly created prefab instance is parented under.
//! /return The optional reference to the prefab created.
virtual Prefab::InstanceOptionalReference CreatePrefab(
const AZStd::vector<AZ::Entity*>& entities, AZStd::vector<AZStd::unique_ptr<Prefab::Instance>>&& nestedPrefabInstances,
AZ::IO::PathView filePath, Prefab::InstanceOptionalReference instanceToParentUnder = AZStd::nullopt) = 0;
//! Instantiate the prefab file provided.
//! /param entityToParentUnder The entity the newly created prefab instance is parented under.
//! /return The optional reference to the prefab instance.
virtual Prefab::InstanceOptionalReference InstantiatePrefab(
AZ::IO::PathView filePath, Prefab::InstanceOptionalReference instanceToParentUnder = AZStd::nullopt) = 0;
virtual Prefab::InstanceOptionalReference GetRootPrefabInstance() = 0;
virtual bool LoadFromStream(AZ::IO::GenericStream& stream, AZStd::string_view filename) = 0;
@@ -19,6 +19,7 @@
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.h>
#include <AzToolsFramework/Prefab/EditorPrefabComponent.h>
#include <AzToolsFramework/Prefab/Instance/InstanceEntityMapperInterface.h>
#include <AzToolsFramework/Prefab/Instance/Instance.h>
#include <AzToolsFramework/Prefab/PrefabDomUtils.h>
#include <AzToolsFramework/Prefab/PrefabLoader.h>
@@ -52,6 +53,10 @@ namespace AzToolsFramework
AZ_Assert(m_loaderInterface != nullptr,
"Couldn't get prefab loader interface, it's a requirement for PrefabEntityOwnership system to work");
m_instanceEntityMapperInterface = AZ::Interface<Prefab::InstanceEntityMapperInterface>::Get();
AZ_Assert(m_instanceEntityMapperInterface != nullptr,
"Couldn't get instance entity mapper interface, it's a requirement for PrefabEntityOwnership system to work");
m_rootInstance = AZStd::unique_ptr<Prefab::Instance>(m_prefabSystemComponent->CreatePrefab({}, {}, "NewLevel.prefab"));
m_sliceOwnershipService.BusConnect(m_entityContextId);
@@ -307,6 +312,28 @@ namespace AzToolsFramework
return AZStd::nullopt;
}
Prefab::InstanceOptionalReference PrefabEditorEntityOwnershipService::InstantiatePrefab(
AZ::IO::PathView filePath, Prefab::InstanceOptionalReference instanceToParentUnder)
{
AZStd::unique_ptr<Prefab::Instance> createdPrefabInstance = m_prefabSystemComponent->InstantiatePrefab(filePath);
if (createdPrefabInstance)
{
if (!instanceToParentUnder)
{
instanceToParentUnder = *m_rootInstance;
}
Prefab::Instance& addedInstance = instanceToParentUnder->get().AddInstance(AZStd::move(createdPrefabInstance));
AZ::Entity* containerEntity = addedInstance.m_containerEntity.get();
HandleEntitiesAdded({containerEntity});
return addedInstance;
}
return AZStd::nullopt;
}
Prefab::InstanceOptionalReference PrefabEditorEntityOwnershipService::GetRootPrefabInstance()
{
AZ_Assert(m_rootInstance, "A valid root prefab instance couldn't be found in PrefabEditorEntityOwnershipService.");
@@ -25,6 +25,7 @@ namespace AzToolsFramework
namespace Prefab
{
class Instance;
class InstanceEntityMapperInterface;
class PrefabSystemComponentInterface;
class PrefabLoaderInterface;
}
@@ -191,6 +192,9 @@ namespace AzToolsFramework
const AZStd::vector<AZ::Entity*>& entities, AZStd::vector<AZStd::unique_ptr<Prefab::Instance>>&& nestedPrefabInstances,
AZ::IO::PathView filePath, Prefab::InstanceOptionalReference instanceToParentUnder) override;
Prefab::InstanceOptionalReference InstantiatePrefab(
AZ::IO::PathView filePath, Prefab::InstanceOptionalReference instanceToParentUnder) override;
Prefab::InstanceOptionalReference GetRootPrefabInstance() override;
//////////////////////////////////////////////////////////////////////////
@@ -205,6 +209,7 @@ namespace AzToolsFramework
AZStd::string m_rootPath;
AZStd::unique_ptr<Prefab::Instance> m_rootInstance;
Prefab::InstanceEntityMapperInterface* m_instanceEntityMapperInterface;
Prefab::PrefabSystemComponentInterface* m_prefabSystemComponent;
Prefab::PrefabLoaderInterface* m_loaderInterface;
AzFramework::EntityContextId m_entityContextId;
@@ -149,6 +149,57 @@ namespace AzToolsFramework
return AZ::Success();
}
PrefabOperationResult PrefabPublicHandler::InstantiatePrefab(
AZStd::string_view filePath, AZ::EntityId parent, AZ::Vector3 /*position*/)
{
auto prefabEditorEntityOwnershipInterface = AZ::Interface<PrefabEditorEntityOwnershipInterface>::Get();
if (!prefabEditorEntityOwnershipInterface)
{
return AZ::Failure(AZStd::string("Could not create a new prefab out of the entities provided - internal error "
"(PrefabEditorEntityOwnershipInterface unavailable)."));
}
auto instanceToParentUnder = m_instanceEntityMapperInterface->FindOwningInstance(parent);
if (!instanceToParentUnder)
{
instanceToParentUnder = prefabEditorEntityOwnershipInterface->GetRootPrefabInstance();
if (!parent.IsValid())
{
parent = instanceToParentUnder->get().GetContainerEntityId();
}
}
{
// Initialize Undo Batch object
ScopedUndoBatch undoBatch("Initialize Prefab");
PrefabDom instanceToParentUnderDomBeforeCreate;
m_instanceToTemplateInterface->GenerateDomForInstance(
instanceToParentUnderDomBeforeCreate, instanceToParentUnder->get());
// Instantiate the Prefab
auto instanceToCreate = prefabEditorEntityOwnershipInterface->InstantiatePrefab(filePath, instanceToParentUnder);
if (!instanceToCreate)
{
return AZ::Failure(AZStd::string("Could not instantiate the prefab provided - internal error "
"(A null instance is returned)."));
}
PrefabUndoHelpers::UpdatePrefabInstance(
instanceToParentUnder->get(), "Update prefab instance", instanceToParentUnderDomBeforeCreate, undoBatch.GetUndoBatch());
CreateLink({GetEntityById(parent)}, instanceToCreate->get(), instanceToParentUnder->get().GetTemplateId(),
undoBatch.GetUndoBatch(), parent);
AZ::EntityId containerEntityId = instanceToCreate->get().GetContainerEntityId();
// TODO - apply position
}
return AZ::Success();
}
PrefabOperationResult PrefabPublicHandler::FindCommonRootOwningInstance(
const AZStd::vector<AZ::EntityId>& entityIds, EntityList& inputEntityList, EntityList& topLevelEntities,
AZ::EntityId& commonRootEntityId, InstanceOptionalReference& commonRootEntityOwningInstance)
@@ -210,19 +261,16 @@ namespace AzToolsFramework
m_instanceToTemplateInterface->GeneratePatch(patch, containerEntityDomBefore, containerEntityDomAfter);
m_instanceToTemplateInterface->AppendEntityAliasToPatchPaths(patch, containerEntityId);
PrefabUndoHelpers::CreateLink(
LinkId linkId = PrefabUndoHelpers::CreateLink(
sourceInstance.GetTemplateId(), targetTemplateId, patch, sourceInstance.GetInstanceAlias(),
undoBatch);
sourceInstance.SetLinkId(linkId);
// Update the cache - this prevents these changes from being stored in the regular undo/redo nodes
m_prefabUndoCache.Store(containerEntityId, AZStd::move(containerEntityDomAfter));
}
PrefabOperationResult PrefabPublicHandler::InstantiatePrefab(AZStd::string_view /*filePath*/, AZ::EntityId /*parent*/, AZ::Vector3 /*position*/)
{
return AZ::Failure(AZStd::string("Prefab - InstantiatePrefab is yet to be implemented."));
}
PrefabOperationResult PrefabPublicHandler::SavePrefab(AZ::IO::Path filePath)
{
auto prefabSystemComponentInterface = AZ::Interface<PrefabSystemComponentInterface>::Get();
@@ -318,45 +366,57 @@ namespace AzToolsFramework
return AZ::Success(entityId);
}
void PrefabPublicHandler::GenerateUndoNodesForEntityChangeAndUpdateCache(
AZ::EntityId entityId, UndoSystem::URSequencePoint* parentUndoBatch)
void PrefabPublicHandler::GenerateUndoNodesForEntityChangeAndUpdateCache(
AZ::EntityId entityId, UndoSystem::URSequencePoint* parentUndoBatch)
{
// Create Undo node on entities if they belong to an instance
InstanceOptionalReference owningInstance = m_instanceEntityMapperInterface->FindOwningInstance(entityId);
if (owningInstance.has_value())
{
PrefabDom afterState;
AZ::Entity* entity = GetEntityById(entityId);
if (entity)
{
// Create Undo node on entities if they belong to an instance
InstanceOptionalReference instanceOptionalReference = m_instanceEntityMapperInterface->FindOwningInstance(entityId);
PrefabDom beforeState;
m_prefabUndoCache.Retrieve(entityId, beforeState);
if (instanceOptionalReference.has_value())
m_instanceToTemplateInterface->GenerateDomForEntity(afterState, *entity);
PrefabDom patch;
m_instanceToTemplateInterface->GeneratePatch(patch, beforeState, afterState);
if (patch.IsArray() && !patch.Empty() && beforeState.IsObject())
{
PrefabDom afterState;
AZ::Entity* entity = GetEntityById(entityId);
if (entity)
if (IsInstanceContainerEntity(entityId) && !IsLevelInstanceContainerEntity(entityId))
{
PrefabDom beforeState;
m_prefabUndoCache.Retrieve(entityId, beforeState);
// Save these changes as patches to the link
PrefabUndoLinkUpdate* linkUpdate = aznew PrefabUndoLinkUpdate(AZStd::to_string(static_cast<AZ::u64>(entityId)));
linkUpdate->SetParent(parentUndoBatch);
linkUpdate->Capture(patch, owningInstance->get().GetLinkId());
m_instanceToTemplateInterface->GenerateDomForEntity(afterState, *entity);
PrefabDom patch;
m_instanceToTemplateInterface->GeneratePatch(patch, beforeState, afterState);
if (patch.IsArray() && !patch.Empty() && beforeState.IsObject())
{
// Update the state of the entity
PrefabUndoEntityUpdate* state = aznew PrefabUndoEntityUpdate(AZStd::to_string(static_cast<AZ::u64>(entityId)));
state->SetParent(parentUndoBatch);
state->Capture(beforeState, afterState, entityId);
state->Redo();
}
// Update the cache
m_prefabUndoCache.Store(entityId, AZStd::move(afterState));
linkUpdate->Redo();
}
else
{
m_prefabUndoCache.PurgeCache(entityId);
// Update the state of the entity
PrefabUndoEntityUpdate* state = aznew PrefabUndoEntityUpdate(AZStd::to_string(static_cast<AZ::u64>(entityId)));
state->SetParent(parentUndoBatch);
state->Capture(beforeState, afterState, entityId);
state->Redo();
}
}
// Update the cache
m_prefabUndoCache.Store(entityId, AZStd::move(afterState));
}
else
{
m_prefabUndoCache.PurgeCache(entityId);
}
}
}
bool PrefabPublicHandler::IsInstanceContainerEntity(AZ::EntityId entityId) const
{
@@ -260,6 +260,29 @@ namespace AzToolsFramework
}
}
AZStd::unique_ptr<Instance> PrefabSystemComponent::InstantiatePrefab(AZ::IO::PathView filePath)
{
// Retrieve the template id for the source prefab filepath
Prefab::TemplateId templateId = GetTemplateIdFromFilePath(filePath);
if (templateId == Prefab::InvalidTemplateId)
{
// Load the template from the file
templateId = m_prefabLoader.LoadTemplateFromFile(filePath);
}
if (templateId == Prefab::InvalidTemplateId)
{
AZ_Error("Prefab", false,
"Could not load template from path %s during InstantiatePrefab. Unable to proceed",
filePath);
return nullptr;
}
return InstantiatePrefab(templateId);
}
AZStd::unique_ptr<Instance> PrefabSystemComponent::InstantiatePrefab(const TemplateId& templateId)
{
TemplateReference instantiatingTemplate = FindTemplate(templateId);
@@ -115,9 +115,16 @@ namespace AzToolsFramework
*/
void RemoveAllTemplates() override;
/**
* Generates a new Prefab Instance based on the Template whose source is stored in filepath.
* @param filePath the path to the prefab source file containing the template being instantiated.
* @return A unique_ptr to the newly instantiated instance. Null if operation failed.
*/
AZStd::unique_ptr<Instance> InstantiatePrefab(AZ::IO::PathView filePath) override;
/**
* Generates a new Prefab Instance based on the Template referenced by templateId
* @param templateId the id of the template being instantiated
* @param templateId the id of the template being instantiated.
* @return A unique_ptr to the newly instantiated instance. Null if operation failed.
*/
AZStd::unique_ptr<Instance> InstantiatePrefab(const TemplateId& templateId) override;
@@ -58,6 +58,7 @@ namespace AzToolsFramework
virtual void UpdatePrefabTemplate(TemplateId templateId, const PrefabDom& updatedDom) = 0;
virtual void PropagateTemplateChanges(TemplateId templateId) = 0;
virtual AZStd::unique_ptr<Instance> InstantiatePrefab(AZ::IO::PathView filePath) = 0;
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,