Merge branch 'development' of https://github.com/aws-lumberyard-dev/o3de into mnaumov/2372

This commit is contained in:
mnaumov
2021-08-16 15:23:34 -07:00
878 changed files with 10002 additions and 25721 deletions
@@ -46,7 +46,6 @@ namespace AzToolsFramework
bool InstanceToTemplatePropagator::GenerateDomForEntity(PrefabDom& generatedEntityDom, const AZ::Entity& entity)
{
//grab the owning instance so we can use the entityIdMapper in settings
InstanceOptionalReference owningInstance = m_instanceEntityMapperInterface->FindOwningInstance(entity.GetId());
if (!owningInstance)
@@ -54,19 +53,8 @@ namespace AzToolsFramework
AZ_Error("Prefab", false, "Entity does not belong to an instance");
return false;
}
InstanceEntityIdMapper entityIdMapper;
entityIdMapper.SetStoringInstance(owningInstance->get());
//create settings so that the serialized entity dom undergoes mapping from entity id to entity alias
AZ::JsonSerializerSettings settings;
settings.m_metadata.Add(static_cast<AZ::JsonEntityIdSerializer::JsonEntityIdMapper*>(&entityIdMapper));
//generate PrefabDom using Json serialization system
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::Store(
generatedEntityDom, generatedEntityDom.GetAllocator(), entity, settings);
return result.GetOutcome() == AZ::JsonSerializationResult::Outcomes::Success;
return PrefabDomUtils::StoreEntityInPrefabDomFormat(entity, owningInstance->get(), generatedEntityDom);
}
bool InstanceToTemplatePropagator::GenerateDomForInstance(PrefabDom& generatedInstanceDom, const Prefab::Instance& instance)
@@ -185,8 +173,10 @@ namespace AzToolsFramework
else
{
AZ_Error(
"Prefab", result.GetOutcome() != AZ::JsonSerializationResult::Outcomes::PartialSkip,
"Some of the patches are not successfully applied.");
"Prefab",
(result.GetOutcome() != AZ::JsonSerializationResult::Outcomes::Skipped) &&
(result.GetOutcome() != AZ::JsonSerializationResult::Outcomes::PartialSkip),
"Some of the patches were not successfully applied.");
m_prefabSystemComponentInterface->SetTemplateDirtyFlag(templateId, true);
m_prefabSystemComponentInterface->PropagateTemplateChanges(templateId, instanceToExclude);
return true;
@@ -196,7 +196,8 @@ namespace AzToolsFramework
m_sourceTemplateId, m_targetTemplateId);
return false;
}
if (applyPatchResult.GetOutcome() == AZ::JsonSerializationResult::Outcomes::PartialSkip)
if (applyPatchResult.GetOutcome() == AZ::JsonSerializationResult::Outcomes::PartialSkip ||
applyPatchResult.GetOutcome() == AZ::JsonSerializationResult::Outcomes::Skipped)
{
AZ_Error(
"Prefab", false,
@@ -26,6 +26,30 @@ namespace AzToolsFramework
{
namespace PrefabDomUtils
{
namespace Internal
{
AZ::JsonSerializationResult::ResultCode JsonIssueReporter(AZStd::string& scratchBuffer,
AZStd::string_view message, AZ::JsonSerializationResult::ResultCode result, AZStd::string_view path)
{
namespace JSR = AZ::JsonSerializationResult;
if (result.GetProcessing() == JSR::Processing::Halted)
{
scratchBuffer.append(message.begin(), message.end());
scratchBuffer.append("\n Reason: ");
result.AppendToString(scratchBuffer, path);
scratchBuffer.append(".");
AZ_Warning("Prefab Serialization", false, "%s", scratchBuffer.c_str());
scratchBuffer.clear();
return JSR::ResultCode(result.GetTask(), JSR::Outcomes::Skipped);
}
return result;
}
}
PrefabDomValueReference FindPrefabDomValue(PrefabDomValue& parentValue, const char* valueName)
{
PrefabDomValue::MemberIterator valueIterator = parentValue.FindMember(valueName);
@@ -48,7 +72,7 @@ namespace AzToolsFramework
return valueIterator->value;
}
bool StoreInstanceInPrefabDom(const Instance& instance, PrefabDom& prefabDom, StoreInstanceFlags flags)
bool StoreInstanceInPrefabDom(const Instance& instance, PrefabDom& prefabDom, StoreFlags flags)
{
InstanceEntityIdMapper entityIdMapper;
entityIdMapper.SetStoringInstance(instance);
@@ -59,17 +83,27 @@ namespace AzToolsFramework
settings.m_metadata.Add(static_cast<AZ::JsonEntityIdSerializer::JsonEntityIdMapper*>(&entityIdMapper));
settings.m_metadata.Add(&entityIdMapper);
if ((flags & StoreInstanceFlags::StripDefaultValues) != StoreInstanceFlags::StripDefaultValues)
if ((flags & StoreFlags::StripDefaultValues) != StoreFlags::StripDefaultValues)
{
settings.m_keepDefaults = true;
}
if ((flags & StoreInstanceFlags::StoreLinkIds) != StoreInstanceFlags::None)
if ((flags & StoreFlags::StoreLinkIds) != StoreFlags::None)
{
LinkIdMetadata linkIdMetadata;
settings.m_metadata.Add(&linkIdMetadata);
}
AZStd::string scratchBuffer;
auto issueReportingCallback = [&scratchBuffer]
(AZStd::string_view message, AZ::JsonSerializationResult::ResultCode result,
AZStd::string_view path) -> AZ::JsonSerializationResult::ResultCode
{
return Internal::JsonIssueReporter(scratchBuffer, message, result, path);
};
settings.m_reporting = AZStd::move(issueReportingCallback);
AZ::JsonSerializationResult::ResultCode result =
AZ::JsonSerialization::Store(prefabDom, prefabDom.GetAllocator(), instance, settings);
@@ -86,7 +120,38 @@ namespace AzToolsFramework
return true;
}
bool LoadInstanceFromPrefabDom(Instance& instance, const PrefabDom& prefabDom, LoadInstanceFlags flags)
bool StoreEntityInPrefabDomFormat(const AZ::Entity& entity, Instance& owningInstance, PrefabDom& prefabDom, StoreFlags flags)
{
InstanceEntityIdMapper entityIdMapper;
entityIdMapper.SetStoringInstance(owningInstance);
//create settings so that the serialized entity dom undergoes mapping from entity id to entity alias
AZ::JsonSerializerSettings settings;
settings.m_metadata.Add(static_cast<AZ::JsonEntityIdSerializer::JsonEntityIdMapper*>(&entityIdMapper));
if ((flags & StoreFlags::StripDefaultValues) != StoreFlags::StripDefaultValues)
{
settings.m_keepDefaults = true;
}
AZStd::string scratchBuffer;
auto issueReportingCallback = [&scratchBuffer]
(AZStd::string_view message, AZ::JsonSerializationResult::ResultCode result,
AZStd::string_view path) -> AZ::JsonSerializationResult::ResultCode
{
return Internal::JsonIssueReporter(scratchBuffer, message, result, path);
};
settings.m_reporting = AZStd::move(issueReportingCallback);
//generate PrefabDom using Json serialization system
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::Store(
prefabDom, prefabDom.GetAllocator(), entity, settings);
return result.GetOutcome() == AZ::JsonSerializationResult::Outcomes::Success;
}
bool LoadInstanceFromPrefabDom(Instance& instance, const PrefabDom& prefabDom, LoadFlags 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
@@ -95,7 +160,7 @@ namespace AzToolsFramework
InstanceEntityIdMapper entityIdMapper;
entityIdMapper.SetLoadingInstance(instance);
if ((flags & LoadInstanceFlags::AssignRandomEntityId) == LoadInstanceFlags::AssignRandomEntityId)
if ((flags & LoadFlags::AssignRandomEntityId) == LoadFlags::AssignRandomEntityId)
{
entityIdMapper.SetEntityIdGenerationApproach(InstanceEntityIdMapper::EntityIdGenerationApproach::Random);
}
@@ -125,7 +190,7 @@ namespace AzToolsFramework
}
bool LoadInstanceFromPrefabDom(
Instance& instance, const PrefabDom& prefabDom, AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& referencedAssets, LoadInstanceFlags flags)
Instance& instance, const PrefabDom& prefabDom, AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& referencedAssets, LoadFlags 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
@@ -134,7 +199,7 @@ namespace AzToolsFramework
InstanceEntityIdMapper entityIdMapper;
entityIdMapper.SetLoadingInstance(instance);
if ((flags & LoadInstanceFlags::AssignRandomEntityId) == LoadInstanceFlags::AssignRandomEntityId)
if ((flags & LoadFlags::AssignRandomEntityId) == LoadFlags::AssignRandomEntityId)
{
entityIdMapper.SetEntityIdGenerationApproach(InstanceEntityIdMapper::EntityIdGenerationApproach::Random);
}
@@ -167,7 +232,7 @@ namespace AzToolsFramework
}
bool LoadInstanceFromPrefabDom(
Instance& instance, Instance::EntityList& newlyAddedEntities, const PrefabDom& prefabDom, LoadInstanceFlags flags)
Instance& instance, Instance::EntityList& newlyAddedEntities, const PrefabDom& prefabDom, LoadFlags 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
@@ -176,7 +241,7 @@ namespace AzToolsFramework
InstanceEntityIdMapper entityIdMapper;
entityIdMapper.SetLoadingInstance(instance);
if ((flags & LoadInstanceFlags::AssignRandomEntityId) == LoadInstanceFlags::AssignRandomEntityId)
if ((flags & LoadFlags::AssignRandomEntityId) == LoadFlags::AssignRandomEntityId)
{
entityIdMapper.SetEntityIdGenerationApproach(InstanceEntityIdMapper::EntityIdGenerationApproach::Random);
}
@@ -246,15 +311,12 @@ namespace AzToolsFramework
AZ::JsonSerializationResult::ResultCode ApplyPatches(
PrefabDomValue& prefabDomToApplyPatchesOn, PrefabDom::AllocatorType& allocator, const PrefabDomValue& patches)
{
auto issueReportingCallback = [](AZStd::string_view, AZ::JsonSerializationResult::ResultCode result,
AZStd::string_view) -> AZ::JsonSerializationResult::ResultCode
AZStd::string scratchBuffer;
auto issueReportingCallback = [&scratchBuffer]
(AZStd::string_view message, AZ::JsonSerializationResult::ResultCode result,
AZStd::string_view path) -> AZ::JsonSerializationResult::ResultCode
{
using namespace AZ::JsonSerializationResult;
if (result.GetProcessing() == Processing::Halted)
{
return ResultCode(result.GetTask(), Outcomes::PartialSkip);
}
return result;
return Internal::JsonIssueReporter(scratchBuffer, message, result, path);
};
AZ::JsonApplyPatchSettings applyPatchSettings;
@@ -38,7 +38,7 @@ namespace AzToolsFramework
PrefabDomValueReference FindPrefabDomValue(PrefabDomValue& parentValue, const char* valueName);
PrefabDomValueConstReference FindPrefabDomValue(const PrefabDomValue& parentValue, const char* valueName);
enum class StoreInstanceFlags : uint8_t
enum class StoreFlags : uint8_t
{
//! No flags used during the call to LoadInstanceFromPrefabDom.
None = 0,
@@ -51,7 +51,7 @@ namespace AzToolsFramework
//! linkIds to instance dom so any nested prefabs will have linkIds correctly set.
StoreLinkIds = 1 << 1
};
AZ_DEFINE_ENUM_BITWISE_OPERATORS(StoreInstanceFlags);
AZ_DEFINE_ENUM_BITWISE_OPERATORS(StoreFlags);
/**
* Stores a valid Prefab Instance within a Prefab Dom. Useful for generating Templates
@@ -60,9 +60,21 @@ namespace AzToolsFramework
* @param flags Controls behavior such as whether to store default values
* @return bool on whether the operation succeeded
*/
bool StoreInstanceInPrefabDom(const Instance& instance, PrefabDom& prefabDom, StoreInstanceFlags flags = StoreInstanceFlags::None);
bool StoreInstanceInPrefabDom(const Instance& instance, PrefabDom& prefabDom, StoreFlags flags = StoreFlags::None);
enum class LoadInstanceFlags : uint8_t
/**
* Stores a valid entity in Prefab Dom format.
* @param entity The entity to store
* @param owningInstance The instance owning the passed in entity.
* Used for contextualizing the entity's place in a Prefab hierarchy.
* @param prefabDom The prefabDom that will be used to store the entity data
* @param flags controls behavior such as whether to store default values
* @return bool on whether the operation succeeded
*/
bool StoreEntityInPrefabDomFormat(const AZ::Entity& entity, Instance& owningInstance, PrefabDom& prefabDom,
StoreFlags flags = StoreFlags::None);
enum class LoadFlags : uint8_t
{
//! No flags used during the call to LoadInstanceFromPrefabDom.
None = 0,
@@ -70,7 +82,7 @@ namespace AzToolsFramework
//! unique, e.g. when they are duplicates of live entities, this flag will assign them a random new id.
AssignRandomEntityId = 1 << 0
};
AZ_DEFINE_ENUM_BITWISE_OPERATORS(LoadInstanceFlags);
AZ_DEFINE_ENUM_BITWISE_OPERATORS(LoadFlags);
/**
* Loads a valid Prefab Instance from a Prefab Dom. Useful for generating Instances.
@@ -80,7 +92,7 @@ namespace AzToolsFramework
* @return bool on whether the operation succeeded.
*/
bool LoadInstanceFromPrefabDom(
Instance& instance, const PrefabDom& prefabDom, LoadInstanceFlags flags = LoadInstanceFlags::None);
Instance& instance, const PrefabDom& prefabDom, LoadFlags flags = LoadFlags::None);
/**
* Loads a valid Prefab Instance from a Prefab Dom. Useful for generating Instances.
@@ -92,7 +104,7 @@ namespace AzToolsFramework
*/
bool LoadInstanceFromPrefabDom(
Instance& instance, const PrefabDom& prefabDom, AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>>& referencedAssets,
LoadInstanceFlags flags = LoadInstanceFlags::None);
LoadFlags flags = LoadFlags::None);
/**
* Loads a valid Prefab Instance from a Prefab Dom. Useful for generating Instances.
@@ -105,7 +117,7 @@ namespace AzToolsFramework
*/
bool LoadInstanceFromPrefabDom(
Instance& instance, Instance::EntityList& newlyAddedEntities, const PrefabDom& prefabDom,
LoadInstanceFlags flags = LoadInstanceFlags::None);
LoadFlags flags = LoadFlags::None);
inline PrefabDomPath GetPrefabDomInstancePath(const char* instanceName)
{
@@ -300,7 +300,7 @@ namespace AzToolsFramework
}
PrefabDom storedPrefabDom(&loadedTemplateDom->get().GetAllocator());
if (!PrefabDomUtils::StoreInstanceInPrefabDom(loadedPrefabInstance, storedPrefabDom, PrefabDomUtils::StoreInstanceFlags::StoreLinkIds))
if (!PrefabDomUtils::StoreInstanceInPrefabDom(loadedPrefabInstance, storedPrefabDom, PrefabDomUtils::StoreFlags::StoreLinkIds))
{
return false;
}
@@ -328,7 +328,7 @@ namespace AzToolsFramework
PrefabDom storedPrefabDom(&savingTemplateDom->get().GetAllocator());
if (!PrefabDomUtils::StoreInstanceInPrefabDom(savingPrefabInstance, storedPrefabDom,
PrefabDomUtils::StoreInstanceFlags::StripDefaultValues))
PrefabDomUtils::StoreFlags::StripDefaultValues))
{
return false;
}
@@ -61,7 +61,7 @@ namespace AzToolsFramework
m_prefabUndoCache.Destroy();
}
PrefabOperationResult PrefabPublicHandler::CreatePrefab(const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView absolutePath)
PrefabOperationResult PrefabPublicHandler::CreatePrefabInMemory(const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView filePath)
{
EntityList inputEntityList, topLevelEntities;
AZ::EntityId commonRootEntityId;
@@ -73,8 +73,6 @@ namespace AzToolsFramework
return findCommonRootOutcome;
}
AZ_Assert(absolutePath.IsAbsolute(), "CreatePrefab requires an absolute path for saving the initial prefab file.");
InstanceOptionalReference instanceToCreate;
{
// Initialize Undo Batch object
@@ -125,7 +123,7 @@ namespace AzToolsFramework
PrefabDom linkPatchesCopy;
linkPatchesCopy.CopyFrom(linkPatches->get(), linkPatchesCopy.GetAllocator());
nestedInstanceLinkPatchesMap.emplace(nestedInstance, AZStd::move(linkPatchesCopy));
RemoveLink(outInstance, commonRootEntityOwningInstance->get().GetTemplateId(), undoBatch.GetUndoBatch());
instancePtrs.emplace_back(AZStd::move(outInstance));
@@ -139,18 +137,20 @@ namespace AzToolsFramework
if (!prefabEditorEntityOwnershipInterface)
{
return AZ::Failure(AZStd::string("Could not create a new prefab out of the entities provided - internal error "
"(PrefabEditorEntityOwnershipInterface unavailable)."));
"(PrefabEditorEntityOwnershipInterface unavailable)."));
}
// Create the Prefab
AZ_Assert(filePath.IsAbsolute(), "CreatePrefabInMemory requires an absolute file path.");
instanceToCreate = prefabEditorEntityOwnershipInterface->CreatePrefab(
entities, AZStd::move(instancePtrs), m_prefabLoaderInterface->GenerateRelativePath(absolutePath),
entities, AZStd::move(instancePtrs), m_prefabLoaderInterface->GenerateRelativePath(filePath),
commonRootEntityOwningInstance);
if (!instanceToCreate)
{
return AZ::Failure(AZStd::string("Could not create a new prefab out of the entities provided - internal error "
"(A null instance is returned)."));
"(A null instance is returned)."));
}
AZ::EntityId containerEntityId = instanceToCreate->get().GetContainerEntityId();
@@ -218,7 +218,7 @@ namespace AzToolsFramework
linkUpdate.Redo();
}
});
// Create a link between the templates of the newly created instance and the instance it's being parented under.
CreateLink(
instanceToCreate->get(), commonRootEntityOwningInstance->get().GetTemplateId(), undoBatch.GetUndoBatch(),
@@ -255,18 +255,35 @@ namespace AzToolsFramework
// Select Container Entity
{
auto selectionUndo = aznew SelectionCommand({containerEntityId}, "Select Prefab Container Entity");
auto selectionUndo = aznew SelectionCommand({ containerEntityId }, "Select Prefab Container Entity");
selectionUndo->SetParent(undoBatch.GetUndoBatch());
ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::RunRedoSeparately, selectionUndo);
}
}
// Save Template to file
m_prefabLoaderInterface->SaveTemplateToFile(instanceToCreate->get().GetTemplateId(), absolutePath);
return AZ::Success();
}
PrefabOperationResult PrefabPublicHandler::CreatePrefabInDisk(const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView filePath)
{
auto result = CreatePrefabInMemory(entityIds, filePath);
if (result.IsSuccess())
{
// Save Template to file
auto relativePath = m_prefabLoaderInterface->GenerateRelativePath(filePath);
Prefab::TemplateId templateId = m_prefabSystemComponentInterface->GetTemplateIdFromFilePath(relativePath);
if (!m_prefabLoaderInterface->SaveTemplateToFile(templateId, filePath))
{
AZStd::string_view filePathString(filePath);
return AZ::Failure(AZStd::string::format(
"Could not save the newly created prefab to file path %.*s - internal error ",
AZ_STRING_ARG(filePathString)));
}
}
return result;
}
PrefabDom PrefabPublicHandler::ApplyContainerTransformAndGeneratePatch(AZ::EntityId containerEntityId, AZ::EntityId parentEntityId, const EntityList& childEntities)
{
AZ::Entity* containerEntity = GetEntityById(containerEntityId);
@@ -301,7 +318,7 @@ namespace AzToolsFramework
return AZStd::move(patch);
}
PrefabOperationResult PrefabPublicHandler::InstantiatePrefab(
InstantiatePrefabResult PrefabPublicHandler::InstantiatePrefab(
AZStd::string_view filePath, AZ::EntityId parent, const AZ::Vector3& position)
{
auto prefabEditorEntityOwnershipInterface = AZ::Interface<PrefabEditorEntityOwnershipInterface>::Get();
@@ -347,6 +364,7 @@ namespace AzToolsFramework
relativePath.Native().c_str(), instanceToParentUnder->get().GetTemplateSourcePath().Native().c_str()));
}
AZ::EntityId containerEntityId;
{
// Initialize Undo Batch object
ScopedUndoBatch undoBatch("Instantiate Prefab");
@@ -367,7 +385,7 @@ namespace AzToolsFramework
instanceToParentUnder->get(), "Update prefab instance", instanceToParentUnderDomBeforeCreate, undoBatch.GetUndoBatch());
// Create Link with correct container patches
AZ::EntityId containerEntityId = instanceToCreate->get().GetContainerEntityId();
containerEntityId = instanceToCreate->get().GetContainerEntityId();
AZ::Entity* containerEntity = GetEntityById(containerEntityId);
AZ_Assert(containerEntity, "Invalid container entity detected in InstantiatePrefab.");
@@ -394,7 +412,7 @@ namespace AzToolsFramework
&AzToolsFramework::ToolsApplicationRequestBus::Events::ClearDirtyEntities);
}
return AZ::Success();
return AZ::Success(containerEntityId);
}
PrefabOperationResult PrefabPublicHandler::FindCommonRootOwningInstance(
@@ -1727,6 +1745,7 @@ namespace AzToolsFramework
AliasPath absoluteInstancePath = commonOwningInstance.GetAbsoluteInstanceAliasPath();
absoluteInstancePath.Append(newInstanceAlias);
absoluteInstancePath.Append(PrefabDomUtils::ContainerEntityName);
AZ::EntityId newEntityId = InstanceEntityIdMapper::GenerateEntityIdForAliasPath(absoluteInstancePath);
duplicatedEntityIds.push_back(newEntityId);
@@ -42,8 +42,11 @@ namespace AzToolsFramework
void UnregisterPrefabPublicHandlerInterface();
// PrefabPublicInterface...
PrefabOperationResult CreatePrefab(const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView absolutePath) override;
PrefabOperationResult InstantiatePrefab(AZStd::string_view filePath, AZ::EntityId parent, const AZ::Vector3& position) override;
PrefabOperationResult CreatePrefabInDisk(
const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView filePath) override;
PrefabOperationResult CreatePrefabInMemory(
const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView filePath) override;
InstantiatePrefabResult InstantiatePrefab(AZStd::string_view filePath, AZ::EntityId parent, const AZ::Vector3& position) override;
PrefabOperationResult SavePrefab(AZ::IO::Path filePath) override;
PrefabEntityResult CreateEntity(AZ::EntityId parentId, const AZ::Vector3& position) override;
@@ -25,6 +25,7 @@ namespace AzToolsFramework
namespace Prefab
{
typedef AZ::Outcome<void, AZStd::string> PrefabOperationResult;
typedef AZ::Outcome<AZ::EntityId, AZStd::string> InstantiatePrefabResult;
typedef AZ::Outcome<bool, AZStd::string> PrefabRequestResult;
typedef AZ::Outcome<AZ::EntityId, AZStd::string> PrefabEntityResult;
@@ -39,22 +40,34 @@ namespace AzToolsFramework
AZ_RTTI(PrefabPublicInterface, "{931AAE9D-C775-4818-9070-A2DA69489CBE}");
/**
* Create a prefab out of the entities provided, at the path provided.
* Create a prefab out of the entities provided, at the path provided, and save it in disk immediately.
* Automatically detects descendants of entities, and discerns between entities and child instances.
* @param entityIds The entities that should form the new prefab (along with their descendants).
* @param filePath The absolute path for the new prefab file.
* @return An outcome object; on failure, it comes with an error message detailing the cause of the error.
*/
virtual PrefabOperationResult CreatePrefab(const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView absolutePath) = 0;
virtual PrefabOperationResult CreatePrefabInDisk(
const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView filePath) = 0;
/**
* Create a prefab out of the entities provided, at the path provided, and keep it in memory.
* Automatically detects descendants of entities, and discerns between entities and child instances.
* @param entityIds The entities that should form the new prefab (along with their descendants).
* @param filePath The absolute path for the new prefab file.
* @return An outcome object; on failure, it comes with an error message detailing the cause of the error.
*/
virtual PrefabOperationResult CreatePrefabInMemory(
const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView filePath) = 0;
/**
* Instantiate a prefab from a prefab file.
* @param filePath The path to the prefab file to instantiate.
* @param parent The entity the prefab should be a child of in the transform hierarchy.
* @param position The position in world space the prefab should be instantiated in.
* @return An outcome object; on failure, it comes with an error message detailing the cause of the error.
* @return An outcome object with an entityId of the new prefab's container entity;
* on failure, it comes with an error message detailing the cause of the error.
*/
virtual PrefabOperationResult InstantiatePrefab(AZStd::string_view filePath, AZ::EntityId parent, const AZ::Vector3& position) = 0;
virtual InstantiatePrefabResult InstantiatePrefab(AZStd::string_view filePath, AZ::EntityId parent, const AZ::Vector3& position) = 0;
/**
* Saves changes to prefab to disk.
@@ -0,0 +1,56 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Component/EntityId.h>
#include <AzCore/EBus/EBus.h>
#include <AzCore/Math/Vector3.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/string/string_view.h>
namespace AzToolsFramework
{
namespace Prefab
{
/**
* The primary purpose of this bus is to facilitate writing automated tests for prefabs.
* It calls PrefabPublicInterface internally to talk to the prefab system.
* If you would like to integrate prefabs into your system, please call PrefabPublicInterface
* directly for better performance.
*/
class PrefabPublicRequests
: public AZ::EBusTraits
{
public:
using Bus = AZ::EBus<PrefabPublicRequests>;
//////////////////////////////////////////////////////////////////////////
// EBusTraits overrides
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
//////////////////////////////////////////////////////////////////////////
virtual ~PrefabPublicRequests() = default;
/**
* Create a prefab out of the entities provided, at the path provided, and keep it in memory.
* Automatically detects descendants of entities, and discerns between entities and child instances.
*/
virtual bool CreatePrefabInMemory(
const AZStd::vector<AZ::EntityId>& entityIds, AZStd::string_view filePath) = 0;
/**
* Instantiate a prefab from a prefab file.
*/
virtual AZ::EntityId InstantiatePrefab(AZStd::string_view filePath, AZ::EntityId parent, const AZ::Vector3& position) = 0;
};
using PrefabPublicRequestBus = AZ::EBus<PrefabPublicRequests>;
} // namespace Prefab
} // namespace AzToolsFramework
@@ -0,0 +1,79 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzToolsFramework/Prefab/PrefabPublicRequestHandler.h>
#include <AzToolsFramework/Prefab/PrefabPublicInterface.h>
namespace AzToolsFramework
{
namespace Prefab
{
void PrefabPublicRequestHandler::Reflect(AZ::ReflectContext* context)
{
AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
if (behaviorContext)
{
behaviorContext->EBus<PrefabPublicRequestBus>("PrefabPublicRequestBus")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
->Attribute(AZ::Script::Attributes::Category, "Prefab")
->Attribute(AZ::Script::Attributes::Module, "prefab")
->Event("CreatePrefabInMemory", &PrefabPublicRequests::CreatePrefabInMemory)
->Event("InstantiatePrefab", &PrefabPublicRequests::InstantiatePrefab)
;
}
}
void PrefabPublicRequestHandler::Connect()
{
m_prefabPublicInterface = AZ::Interface<Prefab::PrefabPublicInterface>::Get();
AZ_Assert(m_prefabPublicInterface, "PrefabPublicRequestHandler - Could not retrieve instance of PrefabPublicInterface");
PrefabPublicRequestBus::Handler::BusConnect();
}
void PrefabPublicRequestHandler::Disconnect()
{
PrefabPublicRequestBus::Handler::BusDisconnect();
m_prefabPublicInterface = nullptr;
}
bool PrefabPublicRequestHandler::CreatePrefabInMemory(const AZStd::vector<AZ::EntityId>& entityIds, AZStd::string_view filePath)
{
auto createPrefabOutcome = m_prefabPublicInterface->CreatePrefabInMemory(entityIds, filePath);
if (!createPrefabOutcome.IsSuccess())
{
AZ_Error("CreatePrefabInMemory", false,
"Failed to create Prefab on file path '%.*s'. Error message: %s.",
AZ_STRING_ARG(filePath),
createPrefabOutcome.GetError().c_str());
return false;
}
return true;
}
AZ::EntityId PrefabPublicRequestHandler::InstantiatePrefab(AZStd::string_view filePath, AZ::EntityId parent, const AZ::Vector3& position)
{
auto instantiatePrefabOutcome = m_prefabPublicInterface->InstantiatePrefab(filePath, parent, position);
if (!instantiatePrefabOutcome.IsSuccess())
{
AZ_Error("InstantiatePrefab", false,
"Failed to instantiate Prefab on file path '%.*s'. Error message: %s.",
AZ_STRING_ARG(filePath),
instantiatePrefabOutcome.GetError().c_str());
return AZ::EntityId();
}
return instantiatePrefabOutcome.GetValue();
}
} // namespace Prefab
} // namespace AzToolsFramework
@@ -0,0 +1,41 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzToolsFramework/Prefab/PrefabPublicRequestBus.h>
namespace AzToolsFramework
{
namespace Prefab
{
class PrefabPublicInterface;
class PrefabPublicRequestHandler final
: public PrefabPublicRequestBus::Handler
{
public:
AZ_CLASS_ALLOCATOR(PrefabPublicRequestHandler, AZ::SystemAllocator, 0);
AZ_RTTI(PrefabPublicRequestHandler, "{83FBDDF9-10BE-4373-B1DC-44B47EE4805C}");
static void Reflect(AZ::ReflectContext* context);
void Connect();
void Disconnect();
bool CreatePrefabInMemory(const AZStd::vector<AZ::EntityId>& entityIds, AZStd::string_view filePath) override;
AZ::EntityId InstantiatePrefab(AZStd::string_view filePath, AZ::EntityId parent, const AZ::Vector3& position) override;
private:
PrefabPublicInterface* m_prefabPublicInterface = nullptr;
};
} // namespace Prefab
} // namespace AzToolsFramework
@@ -35,12 +35,14 @@ namespace AzToolsFramework
m_instanceUpdateExecutor.RegisterInstanceUpdateExecutorInterface();
m_instanceToTemplatePropagator.RegisterInstanceToTemplateInterface();
m_prefabPublicHandler.RegisterPrefabPublicHandlerInterface();
m_prefabPublicRequestHandler.Connect();
AZ::SystemTickBus::Handler::BusConnect();
}
void PrefabSystemComponent::Deactivate()
{
AZ::SystemTickBus::Handler::BusDisconnect();
m_prefabPublicRequestHandler.Disconnect();
m_prefabPublicHandler.UnregisterPrefabPublicHandlerInterface();
m_instanceToTemplatePropagator.UnregisterInstanceToTemplateInterface();
m_instanceUpdateExecutor.UnregisterInstanceUpdateExecutorInterface();
@@ -54,6 +56,7 @@ namespace AzToolsFramework
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabConversionPipeline::Reflect(context);
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabCatchmentProcessor::Reflect(context);
AzToolsFramework::Prefab::PrefabConversionUtils::EditorInfoRemover::Reflect(context);
PrefabPublicRequestHandler::Reflect(context);
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
if (serialize)
@@ -62,7 +65,6 @@ namespace AzToolsFramework
}
AZ::JsonRegistrationContext* jsonRegistration = azrtti_cast<AZ::JsonRegistrationContext*>(context);
if (jsonRegistration)
{
jsonRegistration->Serializer<JsonInstanceSerializer>()->HandlesType<Instance>();
@@ -24,6 +24,7 @@
#include <AzToolsFramework/Prefab/PrefabIdTypes.h>
#include <AzToolsFramework/Prefab/PrefabLoader.h>
#include <AzToolsFramework/Prefab/PrefabPublicHandler.h>
#include <AzToolsFramework/Prefab/PrefabPublicRequestHandler.h>
#include <AzToolsFramework/Prefab/PrefabSystemComponentInterface.h>
#include <AzToolsFramework/Prefab/Template/Template.h>
@@ -369,6 +370,9 @@ namespace AzToolsFramework
// Used for updating Templates when Instances are modified
InstanceToTemplatePropagator m_instanceToTemplatePropagator;
// Handler of the public Prefab requests
PrefabPublicRequestHandler m_prefabPublicRequestHandler;
};
} // namespace Prefab
} // namespace AzToolsFramework
@@ -266,8 +266,8 @@ namespace AzToolsFramework
AZ_Error(
"Prefab",
result.GetOutcome() == AZ::JsonSerializationResult::Outcomes::PartialSkip ||
result.GetOutcome() == AZ::JsonSerializationResult::Outcomes::Success,
(result.GetOutcome() != AZ::JsonSerializationResult::Outcomes::Skipped) &&
(result.GetOutcome() != AZ::JsonSerializationResult::Outcomes::PartialSkip),
"Some of the patches are not successfully applied.");
//remove the link id placed into the instance
@@ -513,7 +513,7 @@ exportComponent, prefabProcessorContext);
// convert Prefab DOM into Prefab Instance.
AZStd::unique_ptr<Instance> instance(aznew Instance());
if (!Prefab::PrefabDomUtils::LoadInstanceFromPrefabDom(*instance, prefab,
Prefab::PrefabDomUtils::LoadInstanceFlags::AssignRandomEntityId))
Prefab::PrefabDomUtils::LoadFlags::AssignRandomEntityId))
{
PrefabDomValueReference sourceReference = PrefabDomUtils::FindPrefabDomValue(prefab, PrefabDomUtils::SourceName);
@@ -30,7 +30,7 @@ namespace AzToolsFramework::Prefab::SpawnableUtils
{
Instance instance;
if (Prefab::PrefabDomUtils::LoadInstanceFromPrefabDom(instance, prefabDom, referencedAssets,
Prefab::PrefabDomUtils::LoadInstanceFlags::AssignRandomEntityId)) // Always assign random entity ids because the spawnable is
Prefab::PrefabDomUtils::LoadFlags::AssignRandomEntityId)) // Always assign random entity ids because the spawnable is
// going to be used to create clones of the entities.
{
AzFramework::Spawnable::EntityList& entities = spawnable.GetEntities();