Integrating up through commit 90f050496

This commit is contained in:
alexpete
2021-04-07 14:03:29 -07:00
parent 8f2ed080a9
commit c2cbd430fe
2694 changed files with 285622 additions and 176874 deletions
@@ -40,18 +40,18 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
return;
}
prefabProcessorContext.ListPrefabs([this, &serializeContext, &prefabProcessorContext](AZStd::string_view prefabName, PrefabDom& prefab)
{
auto result = RemoveEditorInfo(prefab, serializeContext, prefabProcessorContext);
if (!result)
prefabProcessorContext.ListPrefabs(
[this, &serializeContext, &prefabProcessorContext](AZStd::string_view prefabName, PrefabDom& prefab)
{
AZ_Assert(false,
"Converting to runtime Prefab '%.*s' failed, Error: %s .",
AZ_STRING_ARG(prefabName),
result.GetError().c_str());
return;
}
});
auto result = RemoveEditorInfo(prefab, serializeContext, prefabProcessorContext);
if (!result)
{
AZ_Error(
"Prefab", false, "Converting to runtime Prefab '%.*s' failed, Error: %s .", AZ_STRING_ARG(prefabName),
result.GetError().c_str());
return;
}
});
}
void EditorInfoRemover::Reflect(AZ::ReflectContext* context)
@@ -74,6 +74,12 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
}
);
if (instance->HasContainerEntity())
{
auto containerEntityReference = instance->GetContainerEntity();
result.emplace_back(&containerEntityReference->get());
}
return result;
}
@@ -519,7 +525,8 @@ exportComponent, prefabProcessorContext);
// convert Prefab DOM into Prefab Instance.
AZStd::unique_ptr<Instance> instance(aznew Instance());
if (!Prefab::PrefabDomUtils::LoadInstanceFromPrefabDom(*instance, prefab, false))
if (!Prefab::PrefabDomUtils::LoadInstanceFromPrefabDom(*instance, prefab,
Prefab::PrefabDomUtils::LoadInstanceFlags::AssignRandomEntityId))
{
PrefabDomValueReference sourceReference = PrefabDomUtils::FindPrefabDomValue(prefab, PrefabDomUtils::SourceName);
@@ -613,19 +620,28 @@ exportComponent, prefabProcessorContext);
[&exportEntitiesMap](AZStd::unique_ptr<AZ::Entity>& entity)
{
auto entityId = entity->GetId();
entity.release();
entity.reset(exportEntitiesMap[entityId]);
return true;
}
);
if (instance->HasContainerEntity())
{
if (auto found = exportEntitiesMap.find(instance->GetContainerEntityId()); found != exportEntitiesMap.end())
{
instance->SetContainerEntity(*found->second);
}
}
// save the final result in the target Prefab DOM.
if (!PrefabDomUtils::StoreInstanceInPrefabDom(*instance, prefab))
PrefabDom filteredPrefab;
if (!PrefabDomUtils::StoreInstanceInPrefabDom(*instance, filteredPrefab))
{
return AZ::Failure(AZStd::string::format(
"Saving exported Prefab Instance within a Prefab Dom failed.")
);
}
prefab.Swap(filteredPrefab);
return AZ::Success();
}
@@ -16,6 +16,7 @@
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/Utils.h>
#include <AzFramework/Spawnable/Spawnable.h>
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
#include <AzToolsFramework/Prefab/Spawnable/PrefabCatchmentProcessor.h>
#include <AzToolsFramework/Prefab/Spawnable/SpawnableUtils.h>
@@ -23,9 +24,11 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
{
void PrefabCatchmentProcessor::Process(PrefabProcessorContext& context)
{
context.ListPrefabs([&context](AZStd::string_view prefabName, PrefabDom& prefab)
AZ::DataStream::StreamType serializationFormat = m_serializationFormat == SerializationFormats::Binary ?
AZ::DataStream::StreamType::ST_BINARY : AZ::DataStream::StreamType::ST_XML;
context.ListPrefabs([&context, serializationFormat](AZStd::string_view prefabName, PrefabDom& prefab)
{
ProcessPrefab(context, prefabName, prefab);
ProcessPrefab(context, prefabName, prefab, serializationFormat);
});
}
@@ -33,31 +36,61 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
{
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context); serializeContext != nullptr)
{
serializeContext->Class<PrefabCatchmentProcessor, PrefabProcessor>()->Version(1);
serializeContext->Enum<SerializationFormats>()
->Value("Binary", SerializationFormats::Binary)
->Value("Text", SerializationFormats::Text);
serializeContext->Class<PrefabCatchmentProcessor, PrefabProcessor>()
->Version(2)
->Field("SerializationFormat", &PrefabCatchmentProcessor::m_serializationFormat);
}
}
void PrefabCatchmentProcessor::ProcessPrefab(PrefabProcessorContext& context, AZStd::string_view prefabName, PrefabDom& prefab)
void PrefabCatchmentProcessor::ProcessPrefab(PrefabProcessorContext& context, AZStd::string_view prefabName, PrefabDom& prefab,
AZ::DataStream::StreamType serializationFormat)
{
AZStd::string uniqueName = prefabName;
uniqueName += '.';
uniqueName += AzFramework::Spawnable::FileExtension;
uniqueName += AzFramework::Spawnable::DotFileExtension;
auto serializer = [](AZStd::vector<uint8_t>& output, const ProcessedObjectStore& object) -> bool
auto serializer = [serializationFormat](AZStd::vector<uint8_t>& output, const ProcessedObjectStore& object) -> bool
{
AZ::IO::ByteContainerStream stream(&output);
return AZ::Utils::SaveObjectToStream(stream, AZ::DataStream::StreamType::ST_BINARY,
AZStd::any_cast<void>(&object.GetObject()), object.GetObject().type());
auto& asset = object.GetAsset();
return AZ::Utils::SaveObjectToStream(stream, serializationFormat, &asset, asset.GetType());
};
auto spawnable = SpawnableUtils::CreateSpawnable(prefab);
SpawnableUtils::SortEntitiesByTransformHierarchy(spawnable);
AZStd::any spawnableAny(AZStd::move(spawnable));
auto&& [object, spawnable] = ProcessedObjectStore::Create<AzFramework::Spawnable>(
AZStd::move(uniqueName), context.GetSourceUuid(), AZStd::move(serializer));
AZ_Assert(spawnable, "Failed to create a new spawnable.");
context.GetProcessedObjects().emplace_back(AZStd::move(uniqueName), AZStd::move(spawnableAny),
AZStd::move(serializer), AZ::AzTypeInfo<AzFramework::Spawnable>::Uuid());
bool result = SpawnableUtils::CreateSpawnable(*spawnable, prefab);
if (result)
{
AzFramework::Spawnable::EntityList& entities = spawnable->GetEntities();
for (auto it = entities.begin(); it != entities.end(); )
{
(*it)->InvalidateDependencies();
AZ::Entity::DependencySortOutcome evaluation = (*it)->EvaluateDependenciesGetDetails();
if (evaluation.IsSuccess())
{
++it;
}
else
{
AZ_Error("Prefabs", false, "Entity '%s' %s cannot be activated for the following reason: %s",
(*it)->GetName().c_str(), (*it)->GetId().ToString().c_str(), evaluation.GetError().m_message.c_str());
it = entities.erase(it);
}
}
SpawnableUtils::SortEntitiesByTransformHierarchy(*spawnable);
context.GetProcessedObjects().push_back(AZStd::move(object));
context.RemovePrefab(prefabName);
context.RemovePrefab(prefabName);
}
else
{
AZ_Error("Prefabs", false, "Failed to convert prefab '%.*s' to a spawnable.", AZ_STRING_ARG(prefabName));
context.ErrorEncountered();
}
}
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
@@ -30,6 +30,13 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
AZ_RTTI(AzToolsFramework::Prefab::PrefabConversionUtils::PrefabCatchmentProcessor,
"{F71E2FBA-22ED-44C7-B4C8-D2CF4B2C7B97}", PrefabProcessor);
//! The format the remaining spawnables are going to be stored in.
enum class SerializationFormats
{
Binary, //!< Binary is generally preferable for performance.
Text //!< Store in text format which is usually slower but helps with debugging.
};
~PrefabCatchmentProcessor() override = default;
void Process(PrefabProcessorContext& context) override;
@@ -37,6 +44,15 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
static void Reflect(AZ::ReflectContext* context);
protected:
static void ProcessPrefab(PrefabProcessorContext& context, AZStd::string_view prefabName, PrefabDom& prefab);
static void ProcessPrefab(PrefabProcessorContext& context, AZStd::string_view prefabName, PrefabDom& prefab,
AZ::DataStream::StreamType serializationFormat);
SerializationFormats m_serializationFormat{ SerializationFormats::Binary };
};
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
namespace AZ
{
AZ_TYPE_INFO_SPECIALIZE(AzToolsFramework::Prefab::PrefabConversionUtils::PrefabCatchmentProcessor::SerializationFormats,
"{0FBE2482-B514-4256-8716-EA3ECDF8CD49}");
}
@@ -25,7 +25,30 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
auto registry = AZ::SettingsRegistry::Get();
AZ_Assert(registry, "PrefabConversionPipeline is created before the Settings Registry is available.");
return registry->GetObject(m_processors, registryKey);
bool result = registry->GetObject(m_processors, registryKey);
if (!result)
{
m_processors.clear();
}
AZ::SerializeContext* serializeContext = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
if (serializeContext)
{
m_fingerprint = CalculateProcessorFingerprint(serializeContext);
}
else
{
AZ_Error("PrefabConversionPipeline", false, "Failed to get serialization context");
}
return result;
}
bool PrefabConversionPipeline::IsLoaded() const
{
return !m_processors.empty();
}
void PrefabConversionPipeline::ProcessPrefab(PrefabProcessorContext& context)
@@ -35,6 +58,26 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
processor->Process(context);
}
}
size_t PrefabConversionPipeline::CalculateProcessorFingerprint(AZ::SerializeContext* context)
{
size_t fingerprint = 0;
for (const auto& processor : m_processors)
{
const AZ::SerializeContext::ClassData* classData = context->FindClassData(processor->RTTI_GetType());
if (!classData)
{
AZ_Warning("PrefabConversionPipeline", false, "Class data for processor type %s not found. Cannot get version for fingerprinting", processor->RTTI_GetType().ToString<AZStd::string>().c_str());
continue;
}
AZStd::hash_combine(fingerprint, processor->RTTI_GetType());
AZStd::hash_combine(fingerprint, classData->m_version);
}
return fingerprint;
}
void PrefabConversionPipeline::Reflect(AZ::ReflectContext* context)
{
@@ -45,4 +88,9 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
serializeContext->RegisterGenericType<PrefabProcessorListEntry>();
}
}
size_t PrefabConversionPipeline::GetFingerprint() const
{
return m_fingerprint;
}
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
@@ -31,12 +31,18 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
using PrefabProcessorList = AZStd::vector<PrefabProcessorListEntry>;
bool LoadStackProfile(AZStd::string_view stackProfile);
bool IsLoaded() const;
void ProcessPrefab(PrefabProcessorContext& context);
static void Reflect(AZ::ReflectContext* context);
size_t GetFingerprint() const;
static void Reflect(AZ::ReflectContext* context);
private:
size_t CalculateProcessorFingerprint(AZ::SerializeContext* context);
PrefabProcessorList m_processors;
size_t m_fingerprint{};
};
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
@@ -14,6 +14,10 @@
namespace AzToolsFramework::Prefab::PrefabConversionUtils
{
PrefabProcessorContext::PrefabProcessorContext(const AZ::Uuid& sourceUuid)
: m_sourceUuid(sourceUuid)
{}
bool PrefabProcessorContext::AddPrefab(AZStd::string prefabName, PrefabDom prefab)
{
auto result = m_prefabs.emplace(AZStd::move(prefabName), AZStd::move(prefab));
@@ -76,9 +80,28 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
return m_products;
}
void PrefabProcessorContext::SetPlatformTags(AZ::PlatformTagSet tags)
{
m_platformTags = AZStd::move(tags);
}
const AZ::PlatformTagSet& PrefabProcessorContext::GetPlatformTags() const
{
return m_platformTags;
}
const AZ::Uuid& PrefabProcessorContext::GetSourceUuid() const
{
return m_sourceUuid;
}
bool PrefabProcessorContext::HasCompletedSuccessfully() const
{
return m_completedSuccessfully;
}
void PrefabProcessorContext::ErrorEncountered()
{
m_completedSuccessfully = false;
}
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
@@ -33,6 +33,7 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
AZ_CLASS_ALLOCATOR(PrefabProcessorContext, AZ::SystemAllocator, 0);
AZ_RTTI(PrefabProcessorContext, "{C7D77E3A-C544-486B-B774-7C82C38FE22F}");
explicit PrefabProcessorContext(const AZ::Uuid& sourceUuid);
virtual ~PrefabProcessorContext() = default;
virtual bool AddPrefab(AZStd::string prefabName, PrefabDom prefab);
@@ -44,7 +45,12 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
virtual ProcessedObjectStoreContainer& GetProcessedObjects();
virtual const ProcessedObjectStoreContainer& GetProcessedObjects() const;
virtual void SetPlatformTags(AZ::PlatformTagSet tags);
virtual const AZ::PlatformTagSet& GetPlatformTags() const;
virtual const AZ::Uuid& GetSourceUuid() const;
virtual bool HasCompletedSuccessfully() const;
virtual void ErrorEncountered();
protected:
using NamedPrefabContainer = AZStd::unordered_map<AZStd::string, PrefabDom>;
@@ -53,6 +59,8 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
ProcessedObjectStoreContainer m_products;
AZStd::vector<AZStd::string> m_delayedDelete;
AZ::PlatformTagSet m_platformTags;
AZ::Uuid m_sourceUuid;
bool m_isIterating{ false };
bool m_completedSuccessfully{ true };
};
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
@@ -11,25 +11,21 @@
*/
#include <AzCore/Casting/lossy_cast.h>
#include <AzCore/Math/Uuid.h>
#include <AzToolsFramework/Prefab/Spawnable/ProcesedObjectStore.h>
namespace AzToolsFramework::Prefab::PrefabConversionUtils
{
ProcessedObjectStore::ProcessedObjectStore(AZStd::string uniqueId, AZStd::any object, SerializerFunction objectSerializer,
AZ::Data::AssetType assetType)
ProcessedObjectStore::ProcessedObjectStore(AZStd::string uniqueId, AZStd::unique_ptr<AZ::Data::AssetData> asset, SerializerFunction assetSerializer)
: m_uniqueId(AZStd::move(uniqueId))
, m_object(AZStd::move(object))
, m_objectSerializer(AZStd::move(objectSerializer))
, m_assetType(AZStd::move(assetType))
{
}
, m_assetSerializer(AZStd::move(assetSerializer))
, m_asset(AZStd::move(asset))
{}
bool ProcessedObjectStore::Serialize(AZStd::vector<uint8_t>& output) const
{
if (m_objectSerializer)
if (m_assetSerializer)
{
return m_objectSerializer(output, *this);
return m_assetSerializer(output, *this);
}
else
{
@@ -37,25 +33,38 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
}
}
const AZStd::any& ProcessedObjectStore::GetObject() const
bool ProcessedObjectStore::HasAsset() const
{
return m_object;
}
AZStd::any ProcessedObjectStore::ReleaseObject()
{
return AZStd::move(m_object);
}
uint32_t ProcessedObjectStore::BuildSubId() const
{
AZ::Uuid subIdHash = AZ::Uuid::CreateData(m_uniqueId.data(), m_uniqueId.size());
return azlossy_caster(subIdHash.GetHash());
return m_asset != nullptr;
}
const AZ::Data::AssetType& ProcessedObjectStore::GetAssetType() const
{
return m_assetType;
AZ_Assert(m_asset, "Called GetAssetType on ProcessedObjectStore when there was no valid asset.");
return m_asset->GetType();
}
AZ::Data::AssetData& ProcessedObjectStore::GetAsset()
{
AZ_Assert(m_asset, "Called GetAsset on ProcessedObjectStore when there was no valid asset.");
return *m_asset;
}
const AZ::Data::AssetData& ProcessedObjectStore::GetAsset() const
{
AZ_Assert(m_asset, "Called GetAsset on ProcessedObjectStore when there was no valid asset.");
return *m_asset;
}
AZStd::unique_ptr<AZ::Data::AssetData> ProcessedObjectStore::ReleaseAsset()
{
return AZStd::move(m_asset);
}
uint32_t ProcessedObjectStore::BuildSubId(AZStd::string_view id)
{
AZ::Uuid subIdHash = AZ::Uuid::CreateData(id.data(), id.size());
return azlossy_caster(subIdHash.GetHash());
}
const AZStd::string& ProcessedObjectStore::GetId() const
@@ -13,10 +13,11 @@
#pragma once
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/IO/Path/Path.h>
#include <AzCore/std/any.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/functional.h>
#include <AzCore/std/utils.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzCore/std/typetraits/typetraits.h>
namespace AzToolsFramework::Prefab::PrefabConversionUtils
{
@@ -31,26 +32,42 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils
//! Constructs a new instance.
//! @param uniqueId A name for the object that's unique within the scope of the Prefab. This name will be used to generate a sub id for the product
//! which requires that the name is stable between runs.
//! @param object The object that generated during processing of a Prefab.
//! @param objectSerializer The callback used to convert the provided object into a binary stream.
//! @param assetType The asset type of the asset.
//! @param storagePath The relative path where the asset will be stored if/when committed to disk.
ProcessedObjectStore(AZStd::string uniqueId, AZStd::any object, SerializerFunction objectSerializer, AZ::Data::AssetType assetType);
//! which requires that the name to be stable between runs.
//! @param sourceId The uuid for the source file.
//! @param assetSerializer The callback used to convert the provided asset into a binary version.
template<typename T>
static AZStd::pair<ProcessedObjectStore, T*> Create(AZStd::string uniqueId, const AZ::Uuid& sourceId,
SerializerFunction assetSerializer);
bool Serialize(AZStd::vector<uint8_t>& output) const;
uint32_t BuildSubId() const;
const AZStd::any& GetObject() const;
AZStd::any ReleaseObject();
static uint32_t BuildSubId(AZStd::string_view id);
bool HasAsset() const;
const AZ::Data::AssetType& GetAssetType() const;
const AZ::Data::AssetData& GetAsset() const;
AZ::Data::AssetData& GetAsset();
AZStd::unique_ptr<AZ::Data::AssetData> ReleaseAsset();
const AZStd::string& GetId() const;
private:
AZStd::any m_object;
SerializerFunction m_objectSerializer;
AZ::Data::AssetType m_assetType;
ProcessedObjectStore(AZStd::string uniqueId, AZStd::unique_ptr<AZ::Data::AssetData> asset, SerializerFunction assetSerializer);
SerializerFunction m_assetSerializer;
AZStd::unique_ptr<AZ::Data::AssetData> m_asset;
AZStd::string m_uniqueId;
};
template<typename T>
AZStd::pair<ProcessedObjectStore, T*> ProcessedObjectStore::Create(AZStd::string uniqueId, const AZ::Uuid& sourceId,
SerializerFunction assetSerializer)
{
static_assert(AZStd::is_base_of_v<AZ::Data::AssetData, T>,
"ProcessedObjectStore can only be created from a class that derives from AZ::Data::AssetData.");
AZ::Data::AssetId assetId(sourceId, BuildSubId(uniqueId));
auto instance = AZStd::make_unique<T>(assetId, AZ::Data::AssetData::AssetStatus::Ready);
ProcessedObjectStore resultLeft(AZStd::move(uniqueId), AZStd::move(instance), AZStd::move(assetSerializer));
T* resultRight = static_cast<T*>(&resultLeft.GetAsset());
return AZStd::make_pair<ProcessedObjectStore, T*>(AZStd::move(resultLeft), resultRight);
}
} // namespace AzToolsFramework::Prefab::PrefabConversionUtils
@@ -17,9 +17,10 @@
#include <AzCore/Component/TransformBus.h>
#include <AzCore/std/algorithm.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzFramework/Spawnable/Spawnable.h>
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
#include <AzToolsFramework/Prefab/Instance/Instance.h>
#include <AzToolsFramework/Prefab/PrefabDomUtils.h>
#include <AzFramework/Spawnable/Spawnable.h>
namespace AzToolsFramework::Prefab::SpawnableUtils
{
@@ -27,22 +28,35 @@ namespace AzToolsFramework::Prefab::SpawnableUtils
AzFramework::Spawnable CreateSpawnable(const PrefabDom& prefabDom)
{
AzFramework::Spawnable spawnable;
AZStd::unique_ptr<Instance> instance(aznew Instance());
if (!Prefab::PrefabDomUtils::LoadInstanceFromPrefabDom(*instance, prefabDom, false))
[[maybe_unused]] bool result = CreateSpawnable(spawnable, prefabDom);
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)
{
Instance instance;
if (Prefab::PrefabDomUtils::LoadInstanceFromPrefabDom(instance, prefabDom,
Prefab::PrefabDomUtils::LoadInstanceFlags::AssignRandomEntityId)) // Always assign random entity ids because the spawnable is
// going to be used to create clones of the entities.
{
AZ_Assert(false,
"Failed to Load Prefab Instance from given Prefab DOM while Spawnable creation.");
AzFramework::Spawnable::EntityList& entities = spawnable.GetEntities();
if (instance.HasContainerEntity())
{
entities.emplace_back(AZStd::move(instance.DetachContainerEntity()));
}
instance.DetachNestedEntities(
[&entities](AZStd::unique_ptr<AZ::Entity> entity)
{
entities.emplace_back(AZStd::move(entity));
});
return true;
}
else
{
AzFramework::Spawnable::EntityList& entities = spawnable.GetEntities();
instance->DetachNestedEntities([&entities](AZStd::unique_ptr<AZ::Entity> entity)
{
entities.emplace_back(AZStd::move(entity));
});
return false;
}
return spawnable;
}
void OrganizeEntitiesForSorting(
@@ -18,6 +18,7 @@
namespace AzToolsFramework::Prefab::SpawnableUtils
{
AzFramework::Spawnable CreateSpawnable(const PrefabDom& prefabDom);
bool CreateSpawnable(AzFramework::Spawnable& spawnable, const PrefabDom& prefabDom);
void SortEntitiesByTransformHierarchy(AzFramework::Spawnable& spawnable);
} // namespace AzToolsFramework::Prefab::SpawnableUtils