Integrating up through commit 90f050496
This commit is contained in:
@@ -14,22 +14,52 @@ if(NOT PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
endif()
|
||||
|
||||
ly_add_target(
|
||||
NAME Prefab.PrefabBuilder MODULE
|
||||
NAME PrefabBuilder.Static STATIC
|
||||
NAMESPACE Gem
|
||||
FILES_CMAKE
|
||||
prefabbuilder_files.cmake
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
PUBLIC
|
||||
AZ::AzCore
|
||||
AZ::AzToolsFramework
|
||||
AZ::AssetBuilderSDK
|
||||
)
|
||||
|
||||
ly_add_target(
|
||||
NAME PrefabBuilder MODULE
|
||||
NAMESPACE Gem
|
||||
INCLUDE_DIRECTORIES
|
||||
PRIVATE
|
||||
.
|
||||
FILES_CMAKE
|
||||
prefabbuilder_module_files.cmake
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
Gem::PrefabBuilder.Static
|
||||
)
|
||||
|
||||
ly_add_target(
|
||||
NAME PrefabBuilder.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
|
||||
NAMESPACE Gem
|
||||
FILES_CMAKE
|
||||
prefabbuilder_tests_files.cmake
|
||||
INCLUDE_DIRECTORIES
|
||||
PRIVATE
|
||||
.
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
AZ::AzTest
|
||||
Gem::PrefabBuilder.Static
|
||||
)
|
||||
ly_add_googletest(
|
||||
NAME Gem::PrefabBuilder.Tests
|
||||
)
|
||||
|
||||
ly_add_target_dependencies(
|
||||
TARGETS
|
||||
AssetBuilder
|
||||
AssetProcessor
|
||||
AssetProcessorBatch
|
||||
DEPENDENT_TARGETS
|
||||
Gem::Prefab.PrefabBuilder
|
||||
Gem::PrefabBuilder
|
||||
)
|
||||
|
||||
@@ -0,0 +1,340 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "PrefabBuilderComponent.h"
|
||||
|
||||
namespace AZ::Prefab
|
||||
{
|
||||
void PrefabBuilderComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serialize->Class<PrefabBuilderComponent, AZ::Component>()->Version(0)->Attribute(
|
||||
AZ::Edit::Attributes::SystemComponentTags, AZStd::vector<AZ::Crc32>({AssetBuilderSDK::ComponentTags::AssetBuilder}));
|
||||
}
|
||||
}
|
||||
|
||||
AzToolsFramework::Fingerprinting::TypeFingerprint PrefabBuilderComponent::CalculateBuilderFingerprint() const
|
||||
{
|
||||
AzToolsFramework::Fingerprinting::TypeCollection typeCollection = m_typeFingerprinter->GatherAllTypesForComponents();
|
||||
AzToolsFramework::Fingerprinting::TypeFingerprint fingerprint = m_typeFingerprinter->GenerateFingerprintForAllTypes(typeCollection);
|
||||
AZStd::hash_combine(fingerprint, m_pipeline.GetFingerprint());
|
||||
|
||||
return fingerprint;
|
||||
}
|
||||
|
||||
void PrefabBuilderComponent::Activate()
|
||||
{
|
||||
AssetBuilderSDK::AssetBuilderCommandBus::Handler::BusConnect(m_builderId);
|
||||
|
||||
m_pipeline.LoadStackProfile("GameObjectCreation");
|
||||
|
||||
AZ::SerializeContext* serializeContext = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
|
||||
AZ_Assert(serializeContext, "SerializeContext not found");
|
||||
m_typeFingerprinter = AZStd::make_unique<AzToolsFramework::Fingerprinting::TypeFingerprinter>(*serializeContext);
|
||||
|
||||
AzToolsFramework::Fingerprinting::TypeFingerprint fingerprint = CalculateBuilderFingerprint();
|
||||
|
||||
AssetBuilderSDK::AssetBuilderDesc builderDesc;
|
||||
builderDesc.m_name = "Prefab Builder";
|
||||
builderDesc.m_patterns.emplace_back("*.prefab", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard);
|
||||
builderDesc.m_builderType = AssetBuilderSDK::AssetBuilderDesc::AssetBuilderType::External;
|
||||
builderDesc.m_busId = m_builderId;
|
||||
builderDesc.m_analysisFingerprint = AZStd::to_string(fingerprint);
|
||||
builderDesc.m_createJobFunction =
|
||||
[this](const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response) {
|
||||
CreateJobs(request, response);
|
||||
};
|
||||
builderDesc.m_processJobFunction =
|
||||
[this](const AssetBuilderSDK::ProcessJobRequest& request, AssetBuilderSDK::ProcessJobResponse& response) {
|
||||
ProcessJob(request, response);
|
||||
};
|
||||
|
||||
AssetBuilderSDK::AssetBuilderBus::Broadcast(&AssetBuilderSDK::AssetBuilderBusTraits::RegisterBuilderInformation, builderDesc);
|
||||
}
|
||||
|
||||
void PrefabBuilderComponent::Deactivate()
|
||||
{
|
||||
AssetBuilderSDK::AssetBuilderCommandBus::Handler::BusDisconnect(m_builderId);
|
||||
}
|
||||
|
||||
void PrefabBuilderComponent::ShutDown()
|
||||
{
|
||||
m_isShuttingDown = true;
|
||||
}
|
||||
|
||||
AzToolsFramework::Fingerprinting::TypeFingerprint PrefabBuilderComponent::CalculatePrefabFingerprint(
|
||||
const AzToolsFramework::Prefab::PrefabDom& genericDocument) const
|
||||
{
|
||||
AzToolsFramework::Fingerprinting::TypeFingerprint fingerprint = m_pipeline.GetFingerprint();
|
||||
|
||||
// Deserialize all of the entities and their components (for this prefab only)
|
||||
AzToolsFramework::Prefab::Instance::AliasToEntityMap entities;
|
||||
auto entitiesIterator = genericDocument.FindMember(AzToolsFramework::Prefab::PrefabDomUtils::EntitiesName);
|
||||
|
||||
if (entitiesIterator != genericDocument.MemberEnd())
|
||||
{
|
||||
auto&& entitiesJson = entitiesIterator->value;
|
||||
|
||||
if (entitiesJson.IsObject())
|
||||
{
|
||||
JsonSerializationResult::ResultCode result = AZ::JsonSerialization::Load(entities, entitiesJson);
|
||||
|
||||
if (result.GetProcessing() != JsonSerializationResult::Processing::Halted)
|
||||
{
|
||||
// Add the fingerprint of all the components and their types
|
||||
AZStd::hash_combine(fingerprint, m_typeFingerprinter->GenerateFingerprintForAllTypesInObject(&entities));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fingerprint;
|
||||
}
|
||||
|
||||
AZStd::vector<AssetBuilderSDK::SourceFileDependency> PrefabBuilderComponent::GetSourceDependencies(const AzToolsFramework::Prefab::PrefabDom& genericDocument)
|
||||
{
|
||||
AZStd::vector<AssetBuilderSDK::SourceFileDependency> sourceFileDependencies;
|
||||
auto instancesIterator = genericDocument.FindMember(AzToolsFramework::Prefab::PrefabDomUtils::InstancesName);
|
||||
|
||||
if (instancesIterator != genericDocument.MemberEnd())
|
||||
{
|
||||
auto&& instances = instancesIterator->value;
|
||||
|
||||
if (instances.IsObject())
|
||||
{
|
||||
for (auto&& entry : instances.GetObject())
|
||||
{
|
||||
auto sourceIterator = entry.value.FindMember(AzToolsFramework::Prefab::PrefabDomUtils::SourceName);
|
||||
|
||||
if (sourceIterator != entry.value.MemberEnd())
|
||||
{
|
||||
auto&& source = sourceIterator->value;
|
||||
|
||||
if (source.IsString())
|
||||
{
|
||||
sourceFileDependencies.emplace_back(source.GetString(), Uuid::CreateNull());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sourceFileDependencies;
|
||||
}
|
||||
|
||||
void PrefabBuilderComponent::CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response) const
|
||||
{
|
||||
using namespace AzToolsFramework::Prefab;
|
||||
using namespace AzToolsFramework::Prefab::PrefabConversionUtils;
|
||||
|
||||
if (m_isShuttingDown)
|
||||
{
|
||||
response.m_result = AssetBuilderSDK::CreateJobsResultCode::ShuttingDown;
|
||||
return;
|
||||
}
|
||||
|
||||
AZStd::string fullPath;
|
||||
AZ::StringFunc::Path::ConstructFull(request.m_watchFolder.c_str(), request.m_sourceFile.c_str(), fullPath);
|
||||
|
||||
// Load the JSON Dom
|
||||
AZ::Outcome<PrefabDom, AZStd::string> readPrefabFileResult = AzFramework::FileFunc::ReadJsonFile(AZ::IO::Path(fullPath));
|
||||
if (!readPrefabFileResult.IsSuccess())
|
||||
{
|
||||
AZ_Error(
|
||||
"Prefab", false,
|
||||
"PrefabLoader::LoadPrefabFile - Failed to load Prefab file from '%s'."
|
||||
"Error message: '%s'",
|
||||
fullPath.c_str(), readPrefabFileResult.GetError().c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto genericDocument = readPrefabFileResult.TakeValue();
|
||||
|
||||
size_t fingerprint = CalculatePrefabFingerprint(genericDocument);
|
||||
AZStd::vector<AssetBuilderSDK::SourceFileDependency> sourceFileDependencies = GetSourceDependencies(genericDocument);
|
||||
|
||||
for (const AssetBuilderSDK::PlatformInfo& info : request.m_enabledPlatforms)
|
||||
{
|
||||
AssetBuilderSDK::JobDescriptor job;
|
||||
job.m_jobKey = PrefabJobKey;
|
||||
job.SetPlatformIdentifier(info.m_identifier.c_str());
|
||||
job.m_additionalFingerprintInfo = AZStd::to_string(fingerprint);
|
||||
|
||||
// Add a fingerprint job dependency on any referenced prefab so this prefab will rebuild if the dependent fingerprint changes
|
||||
for (const AssetBuilderSDK::SourceFileDependency& sourceFileDependency : sourceFileDependencies)
|
||||
{
|
||||
job.m_jobDependencyList.emplace_back(
|
||||
PrefabJobKey, info.m_identifier, AssetBuilderSDK::JobDependencyType::Fingerprint, sourceFileDependency);
|
||||
}
|
||||
|
||||
response.m_createJobOutputs.push_back(AZStd::move(job));
|
||||
}
|
||||
|
||||
response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success;
|
||||
}
|
||||
|
||||
bool PrefabBuilderComponent::StoreProducts(
|
||||
AZ::IO::PathView tempDirPath,
|
||||
const AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessorContext::ProcessedObjectStoreContainer& store,
|
||||
AZStd::vector<AssetBuilderSDK::JobProduct>& outputProducts) const
|
||||
{
|
||||
outputProducts.reserve(store.size());
|
||||
|
||||
AZStd::vector<uint8_t> data;
|
||||
for (auto& object : store)
|
||||
{
|
||||
AZ_TracePrintf("Prefab Builder", " Serializing Prefab product '%s'.\n", object.GetId().c_str());
|
||||
if (!object.Serialize(data))
|
||||
{
|
||||
AZ_Error("Prefab Builder", false, "Failed to serialize object '%s'.", object.GetId().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::IO::Path productPath = tempDirPath;
|
||||
productPath /= object.GetId();
|
||||
|
||||
AZ_TracePrintf("Prefab Builder", " Storing Prefab product '%s'.\n", object.GetId().c_str());
|
||||
|
||||
AZStd::unique_ptr<AZ::IO::GenericStream> productFile = GetOutputStream(productPath);
|
||||
|
||||
if (!productFile->IsOpen())
|
||||
{
|
||||
AZ_Error("Prefab Builder", false, "Unable to open product file at '%s'.", productPath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (productFile->Write(data.size(), data.data()) != data.size())
|
||||
{
|
||||
AZ_Error("Prefab Builder", false, "Unable to write product file at '%s'.", productPath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
AssetBuilderSDK::JobProduct product;
|
||||
|
||||
if (AssetBuilderSDK::OutputObject(&object.GetAsset(), object.GetAssetType(), productPath.String(), object.GetAssetType(),
|
||||
object.GetAsset().GetId().m_subId, product))
|
||||
{
|
||||
outputProducts.push_back(AZStd::move(product));
|
||||
}
|
||||
|
||||
data.clear();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<AZ::IO::GenericStream> PrefabBuilderComponent::GetOutputStream(const AZ::IO::Path& path) const
|
||||
{
|
||||
return AZStd::make_unique<AZ::IO::FileIOStream>(path.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeCreatePath);
|
||||
}
|
||||
|
||||
bool PrefabBuilderComponent::ProcessPrefab(
|
||||
const AZ::PlatformTagSet& platformTags, const char* filePath, AZ::IO::PathView tempDirPath, const AZ::Uuid& sourceFileUuid,
|
||||
AzToolsFramework::Prefab::PrefabDom& mutableRootDom, AZStd::vector<AssetBuilderSDK::JobProduct>& jobProducts)
|
||||
{
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessorContext context(sourceFileUuid);
|
||||
AZStd::string rootPrefabName;
|
||||
if (!StringFunc::Path::GetFileName(filePath, rootPrefabName))
|
||||
{
|
||||
AZ_Error("Prefab Builder", false, "Unable to extract filename from '%s'.",
|
||||
filePath);
|
||||
return false;
|
||||
}
|
||||
context.AddPrefab(AZStd::move(rootPrefabName), AZStd::move(mutableRootDom));
|
||||
|
||||
context.SetPlatformTags(AZStd::move(platformTags));
|
||||
|
||||
AZ_TracePrintf("Prefab Builder", "Sending Prefab to the processor stack.\n");
|
||||
m_pipeline.ProcessPrefab(context);
|
||||
if (context.HasCompletedSuccessfully())
|
||||
{
|
||||
AZ_TracePrintf("Prefab Builder", "Finalizing products.\n");
|
||||
if (!context.HasPrefabs())
|
||||
{
|
||||
if (StoreProducts(tempDirPath, context.GetProcessedObjects(), jobProducts))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error("Prefab Builder", false, "One or more objects couldn't be committed to disk.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error("Prefab Builder", false, "After processing there were still Prefabs left.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error("Prefab Builder", false, "Failed to fully process the target prefab.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PrefabBuilderComponent::ProcessJob(const AssetBuilderSDK::ProcessJobRequest& request, AssetBuilderSDK::ProcessJobResponse& response)
|
||||
{
|
||||
using namespace AzToolsFramework::Prefab;
|
||||
using namespace AzToolsFramework::Prefab::PrefabConversionUtils;
|
||||
|
||||
if (m_isShuttingDown)
|
||||
{
|
||||
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Cancelled;
|
||||
return;
|
||||
}
|
||||
|
||||
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
|
||||
|
||||
auto* system = AZ::Interface<PrefabSystemComponentInterface>::Get();
|
||||
if (!system)
|
||||
{
|
||||
AZ_Error("Prefab Builder", false, "Prefab system is not available.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto* loader = AZ::Interface<PrefabLoaderInterface>::Get();
|
||||
if (!loader)
|
||||
{
|
||||
AZ_Error("Prefab Builder", false, "Prefab loader is not available.");
|
||||
return;
|
||||
}
|
||||
|
||||
AZ_TracePrintf("Prefab Builder", "Loading Prefab in '%s'.\n", request.m_fullPath.c_str());
|
||||
TemplateId templateId = loader->LoadTemplateFromFile(AZStd::string_view(request.m_fullPath));
|
||||
if (templateId == InvalidTemplateId)
|
||||
{
|
||||
AZ_Error("Prefab Builder", false, "Failed to load Prefab template.");
|
||||
return;
|
||||
}
|
||||
|
||||
PrefabDom mutableRootDom;
|
||||
mutableRootDom.CopyFrom(system->FindTemplateDom(templateId), mutableRootDom.GetAllocator());
|
||||
|
||||
AZ::PlatformTagSet platformTags;
|
||||
const auto& tags = request.m_platformInfo.m_tags;
|
||||
AZStd::for_each(tags.begin(), tags.end(), [&platformTags](const auto& tag) {
|
||||
platformTags.emplace(AZ::Crc32(tag.c_str(), tag.size(), true));
|
||||
});
|
||||
|
||||
if (ProcessPrefab(
|
||||
platformTags, request.m_fullPath.c_str(), request.m_tempDirPath.c_str(), request.m_sourceFileUUID, mutableRootDom,
|
||||
response.m_outputProducts))
|
||||
{
|
||||
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success;
|
||||
}
|
||||
|
||||
AZ_TracePrintf("Prefab Builder", "Cleaning up.\n");
|
||||
system->RemoveAllTemplates();
|
||||
AZ_TracePrintf("Prefab Builder", "Prefab processing completed.\n");
|
||||
}
|
||||
} // namespace AZ::Prefab
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AssetBuilderSDK/AssetBuilderSDK.h>
|
||||
#include <AssetBuilderSDK/SerializationDependencies.h>
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/Module/Module.h>
|
||||
#include <AzCore/Module/DynamicModuleHandle.h>
|
||||
#include <AzFramework/FileFunc/FileFunc.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabSystemComponent.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/PrefabConversionPipeline.h>
|
||||
#include <Fingerprinting/TypeFingerprinter.h>
|
||||
#include <Prefab/PrefabDomUtils.h>
|
||||
|
||||
namespace AZ::Prefab
|
||||
{
|
||||
class PrefabBuilderComponent
|
||||
: public AssetBuilderSDK::AssetBuilderCommandBus::Handler
|
||||
, public AZ::Component
|
||||
{
|
||||
public:
|
||||
static constexpr const char* BuilderId = "{A2E0791C-4607-4363-A7FD-73D01ED49660}";
|
||||
static constexpr const char* PrefabJobKey = "Prefabs";
|
||||
|
||||
AZ_COMPONENT(PrefabBuilderComponent, BuilderId);
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
PrefabBuilderComponent()
|
||||
: m_builderId(BuilderId)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AZ::Component
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ShutDown() override;
|
||||
AzToolsFramework::Fingerprinting::TypeFingerprint CalculateBuilderFingerprint() const;
|
||||
AzToolsFramework::Fingerprinting::TypeFingerprint CalculatePrefabFingerprint(
|
||||
const AzToolsFramework::Prefab::PrefabDom& genericDocument) const;
|
||||
static AZStd::vector<AssetBuilderSDK::SourceFileDependency> GetSourceDependencies(
|
||||
const AzToolsFramework::Prefab::PrefabDom& genericDocument);
|
||||
bool ProcessPrefab(
|
||||
const AZ::PlatformTagSet& platformTags, const char* filePath, AZ::IO::PathView tempDirPath, const AZ::Uuid& sourceFileUuid,
|
||||
AzToolsFramework::Prefab::PrefabDom& mutableRootDom,
|
||||
AZStd::vector<AssetBuilderSDK::JobProduct>& jobProducts);
|
||||
|
||||
protected:
|
||||
virtual AZStd::unique_ptr<AZ::IO::GenericStream> GetOutputStream(const AZ::IO::Path& path) const;
|
||||
|
||||
private:
|
||||
void CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response) const;
|
||||
|
||||
bool StoreProducts(
|
||||
AZ::IO::PathView tempDirPath,
|
||||
const AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessorContext::ProcessedObjectStoreContainer& store,
|
||||
AZStd::vector<AssetBuilderSDK::JobProduct>& outputProducts) const;
|
||||
|
||||
void ProcessJob(const AssetBuilderSDK::ProcessJobRequest& request, AssetBuilderSDK::ProcessJobResponse& response);
|
||||
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabConversionPipeline m_pipeline;
|
||||
AZ::Uuid m_builderId;
|
||||
AZStd::atomic_bool m_isShuttingDown{ false };
|
||||
AZStd::unique_ptr<AzToolsFramework::Fingerprinting::TypeFingerprinter> m_typeFingerprinter;
|
||||
};
|
||||
|
||||
} // namespace AZ::Prefab
|
||||
@@ -10,219 +10,11 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AssetBuilderSDK/AssetBuilderSDK.h>
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/Module/Module.h>
|
||||
#include <AzCore/Module/DynamicModuleHandle.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabSystemComponent.h>
|
||||
#include <AzToolsFramework/Prefab/Spawnable/PrefabConversionPipeline.h>
|
||||
#include <PrefabBuilderComponent.h>
|
||||
|
||||
namespace AZ::Prefab
|
||||
{
|
||||
class PrefabBuilderComponent
|
||||
: public AssetBuilderSDK::AssetBuilderCommandBus::Handler
|
||||
{
|
||||
public:
|
||||
PrefabBuilderComponent()
|
||||
: m_builderId("{A2E0791C-4607-4363-A7FD-73D01ED49660}")
|
||||
{
|
||||
AssetBuilderSDK::AssetBuilderCommandBus::Handler::BusConnect(m_builderId);
|
||||
}
|
||||
|
||||
~PrefabBuilderComponent()
|
||||
{
|
||||
if (m_prefabSystem)
|
||||
{
|
||||
m_prefabSystem->Deactivate();
|
||||
}
|
||||
|
||||
AssetBuilderSDK::AssetBuilderCommandBus::Handler::BusDisconnect(m_builderId);
|
||||
}
|
||||
|
||||
void Register()
|
||||
{
|
||||
AssetBuilderSDK::AssetBuilderDesc builderDesc;
|
||||
builderDesc.m_name = "Prefab Builder";
|
||||
builderDesc.m_patterns.emplace_back("*.prefab", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard);
|
||||
builderDesc.m_builderType = AssetBuilderSDK::AssetBuilderDesc::AssetBuilderType::Internal;
|
||||
builderDesc.m_busId = m_builderId;
|
||||
builderDesc.m_createJobFunction =
|
||||
[this](const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response)
|
||||
{
|
||||
CreateJobs(request, response);
|
||||
};
|
||||
builderDesc.m_processJobFunction =
|
||||
[this](const AssetBuilderSDK::ProcessJobRequest& request, AssetBuilderSDK::ProcessJobResponse& response)
|
||||
{
|
||||
ProcessJob(request, response);
|
||||
};
|
||||
|
||||
AssetBuilderSDK::AssetBuilderBus::Broadcast(&AssetBuilderSDK::AssetBuilderBusTraits::RegisterBuilderInformation, builderDesc);
|
||||
}
|
||||
|
||||
void ShutDown() override
|
||||
{
|
||||
m_isShuttingDown = true;
|
||||
}
|
||||
|
||||
private:
|
||||
void CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response)
|
||||
{
|
||||
if (m_isShuttingDown)
|
||||
{
|
||||
response.m_result = AssetBuilderSDK::CreateJobsResultCode::ShuttingDown;
|
||||
return;
|
||||
}
|
||||
|
||||
for (const AssetBuilderSDK::PlatformInfo& info : request.m_enabledPlatforms)
|
||||
{
|
||||
AssetBuilderSDK::JobDescriptor job;
|
||||
job.m_jobKey = "Prefabs";
|
||||
job.SetPlatformIdentifier(info.m_identifier.c_str());
|
||||
response.m_createJobOutputs.push_back(AZStd::move(job));
|
||||
}
|
||||
|
||||
response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success;
|
||||
}
|
||||
|
||||
bool StoreProducts(const AssetBuilderSDK::ProcessJobRequest& request, AssetBuilderSDK::ProcessJobResponse& response,
|
||||
const AzToolsFramework::Prefab::PrefabConversionUtils::PrefabProcessorContext::ProcessedObjectStoreContainer& store)
|
||||
{
|
||||
response.m_outputProducts.reserve(store.size());
|
||||
|
||||
AZStd::vector<uint8_t> data;
|
||||
for (auto& object : store)
|
||||
{
|
||||
AZ_TracePrintf("Prefab Builder", " Serializing Prefab product '%s'.\n", object.GetId().c_str());
|
||||
if (!object.Serialize(data))
|
||||
{
|
||||
AZ_Error("Prefab Builder", false, "Failed to serialize object '%s'.", object.GetId().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::IO::Path productPath = request.m_tempDirPath;
|
||||
productPath /= object.GetId();
|
||||
|
||||
AZ_TracePrintf("Prefab Builder", " Storing Prefab product '%s'.\n", object.GetId().c_str());
|
||||
|
||||
AZ::IO::SystemFile productFile;
|
||||
if (!productFile.Open(productPath.c_str(),
|
||||
AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY | AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH))
|
||||
{
|
||||
AZ_Error("Prefab Builder", false, "Unable to open product file at '%s'.", productPath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (productFile.Write(data.data(), data.size()) != data.size())
|
||||
{
|
||||
AZ_Error("Prefab Builder", false, "Unable to write product file at '%s'.", productPath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
AssetBuilderSDK::JobProduct product;
|
||||
product.m_productFileName = productPath.String();
|
||||
product.m_productAssetType = object.GetAssetType();
|
||||
product.m_productSubID = object.BuildSubId();
|
||||
|
||||
// TODO: Handle dependencies.
|
||||
product.m_dependenciesHandled = true;
|
||||
|
||||
response.m_outputProducts.push_back(AZStd::move(product));
|
||||
|
||||
data.clear();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ProcessJob(const AssetBuilderSDK::ProcessJobRequest& request, AssetBuilderSDK::ProcessJobResponse& response)
|
||||
{
|
||||
using namespace AzToolsFramework::Prefab;
|
||||
using namespace AzToolsFramework::Prefab::PrefabConversionUtils;
|
||||
|
||||
if (m_isShuttingDown)
|
||||
{
|
||||
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Cancelled;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_prefabSystem)
|
||||
{
|
||||
m_prefabSystem = AZStd::make_unique<AzToolsFramework::Prefab::PrefabSystemComponent>();
|
||||
m_prefabSystem->Init();
|
||||
m_prefabSystem->Activate();
|
||||
|
||||
m_pipeline.LoadStackProfile("GameObjectCreation");
|
||||
}
|
||||
|
||||
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
|
||||
|
||||
auto* system = AZ::Interface<PrefabSystemComponentInterface>::Get();
|
||||
if (!system)
|
||||
{
|
||||
AZ_Error("Prefab Builder", false, "Prefab system is not available.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto* loader = AZ::Interface<PrefabLoaderInterface>::Get();
|
||||
if (!loader)
|
||||
{
|
||||
AZ_Error("Prefab Builder", false, "Prefab loader is not available.");
|
||||
return;
|
||||
}
|
||||
|
||||
AZ_TracePrintf("Prefab Builder", "Loading Prefab in '%s'.\n", request.m_fullPath.c_str());
|
||||
TemplateId templateId = loader->LoadTemplate(request.m_fullPath);
|
||||
if (templateId == InvalidTemplateId)
|
||||
{
|
||||
AZ_Error("Prefab Builder", false, "Failed to load Prefab template.");
|
||||
return;
|
||||
}
|
||||
|
||||
PrefabProcessorContext context;
|
||||
PrefabDom mutableRootDom;
|
||||
// TODO: LoadTemplate should be updated so there's no need to get the extra copy here.
|
||||
mutableRootDom.CopyFrom(system->FindTemplateDom(templateId), mutableRootDom.GetAllocator());
|
||||
AZStd::string rootPrefabName;
|
||||
if (!StringFunc::Path::GetFileName(request.m_fullPath.c_str(), rootPrefabName))
|
||||
{
|
||||
AZ_Warning("Prefab Builder", false, "Unable to extract filename from '%s', using 'Root' instead.",
|
||||
request.m_fullPath.c_str());
|
||||
rootPrefabName = "Root";
|
||||
}
|
||||
context.AddPrefab(AZStd::move(rootPrefabName), AZStd::move(mutableRootDom));
|
||||
|
||||
AZ_TracePrintf("Prefab Builder", "Sending Prefab to the processor stack.\n");
|
||||
m_pipeline.ProcessPrefab(context);
|
||||
|
||||
AZ_TracePrintf("Prefab Builder", "Finalizing products.\n");
|
||||
if (!context.HasPrefabs())
|
||||
{
|
||||
if (StoreProducts(request, response, context.GetProcessedObjects()))
|
||||
{
|
||||
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error("Prefab Builder", false, "One or more objects couldn't be committed to disk.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error("Prefab Builder", false, "After processing there were still Prefabs left.");
|
||||
}
|
||||
|
||||
AZ_TracePrintf("Prefab Builder", "Cleaning up.\n");
|
||||
system->RemoveTemplate(templateId);
|
||||
AZ_TracePrintf("Prefab Builder", "Prefab processing completed.\n");
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<AzToolsFramework::Prefab::PrefabSystemComponent> m_prefabSystem;
|
||||
AzToolsFramework::Prefab::PrefabConversionUtils::PrefabConversionPipeline m_pipeline;
|
||||
AZ::Uuid m_builderId;
|
||||
AZStd::atomic_bool m_isShuttingDown{ false };
|
||||
};
|
||||
|
||||
class PrefabBuilderModule
|
||||
: public Module
|
||||
{
|
||||
@@ -233,20 +25,10 @@ namespace AZ::Prefab
|
||||
PrefabBuilderModule()
|
||||
: Module()
|
||||
{
|
||||
m_builder.Register();
|
||||
m_descriptors.insert(m_descriptors.end(), {
|
||||
PrefabBuilderComponent::CreateDescriptor()
|
||||
});
|
||||
}
|
||||
|
||||
void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.push_back(AZ_CRC_CE("PrefabBuilder"));
|
||||
}
|
||||
|
||||
void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
|
||||
{
|
||||
incompatible.push_back(AZ_CRC_CE("PrefabBuilder"));
|
||||
}
|
||||
|
||||
PrefabBuilderComponent m_builder;
|
||||
};
|
||||
} // namespace AZ::Prefab
|
||||
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "PrefabBuilderTests.h"
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/Serialization/Json/JsonSystemComponent.h>
|
||||
#include <AzCore/Serialization/Json/RegistrationContext.h>
|
||||
#include <AzCore/UserSettings/UserSettingsComponent.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
AZ::Entity* CreateEntity(const char* entityName, AZStd::initializer_list<AZ::Component*> componentsToAdd = {})
|
||||
{
|
||||
// Circumvent the EntityContext system and generate a new entity with a transformcomponent
|
||||
AZ::Entity* newEntity = aznew AZ::Entity(entityName);
|
||||
newEntity->CreateComponent(AZ::TransformComponentTypeId);
|
||||
newEntity->Init();
|
||||
|
||||
for (auto&& component : componentsToAdd)
|
||||
{
|
||||
newEntity->AddComponent(component);
|
||||
}
|
||||
|
||||
newEntity->Activate();
|
||||
|
||||
return newEntity;
|
||||
}
|
||||
|
||||
TEST_F(PrefabBuilderTests, SourceDependencies)
|
||||
{
|
||||
static constexpr const char* ChildPrefabPath = "child.prefab";
|
||||
using namespace AzToolsFramework::Prefab;
|
||||
|
||||
AZStd::vector<AZStd::unique_ptr<Instance>> childInstances;
|
||||
|
||||
auto* prefabSystemComponentInterface = AZ::Interface<PrefabSystemComponentInterface>::Get();
|
||||
auto* prefabLoaderInterface = AZ::Interface<PrefabLoaderInterface>::Get();
|
||||
|
||||
ASSERT_NE(prefabSystemComponentInterface, nullptr);
|
||||
ASSERT_NE(prefabLoaderInterface, nullptr);
|
||||
|
||||
// Create a child entity and a prefab containing it
|
||||
childInstances.push_back(prefabSystemComponentInterface->CreatePrefab({CreateEntity("child")}, {}, ChildPrefabPath));
|
||||
|
||||
// Create a parent entity and a prefab for it, pass in the child prefab for it to reference
|
||||
auto parentInstance = prefabSystemComponentInterface->CreatePrefab({CreateEntity("parent")}, AZStd::move(childInstances), "parent.prefab");
|
||||
|
||||
AZStd::string serializedInstance;
|
||||
|
||||
// Save to a string so we can load it as a PrefabDom and so that the nested instance becomes a Source file reference
|
||||
ASSERT_TRUE(prefabLoaderInterface->SaveTemplateToString(parentInstance->GetTemplateId(), serializedInstance));
|
||||
|
||||
AZ::Outcome<PrefabDom, AZStd::string> readPrefabFileResult = AzFramework::FileFunc::ReadJsonFromString(serializedInstance);
|
||||
|
||||
ASSERT_TRUE(readPrefabFileResult.IsSuccess());
|
||||
|
||||
// Now that we have a PrefabDom, test extracting the Source file reference as a Source Dependency
|
||||
auto sourceFileDependencies = AZ::Prefab::PrefabBuilderComponent::GetSourceDependencies(readPrefabFileResult.TakeValue());
|
||||
|
||||
ASSERT_EQ(sourceFileDependencies.size(), 1);
|
||||
EXPECT_STREQ(sourceFileDependencies[0].m_sourceFileDependencyPath.c_str(), ChildPrefabPath);
|
||||
}
|
||||
|
||||
TEST_F(PrefabBuilderTests, ProductDependencies)
|
||||
{
|
||||
constexpr const char* ChildPrefabPath = "child.prefab";
|
||||
using namespace AzToolsFramework::Prefab;
|
||||
|
||||
AZ::Uuid TestAssetUuid("{7725567D-D420-46C2-B481-E0F79212CD34}");
|
||||
AZ::Data::AssetId TestAssetId(TestAssetUuid, 0);
|
||||
|
||||
AZStd::vector<AZStd::unique_ptr<Instance>> childInstances;
|
||||
|
||||
auto* prefabSystemComponentInterface = AZ::Interface<PrefabSystemComponentInterface>::Get();
|
||||
|
||||
ASSERT_NE(prefabSystemComponentInterface, nullptr);
|
||||
|
||||
auto* component = aznew TestComponent();
|
||||
AZ::Data::Asset<AZ::Data::AssetData> asset = AZ::Data::Asset<TestAsset>(TestAssetId, azrtti_typeid<TestAsset>());
|
||||
component->m_asset = asset;
|
||||
AZ::Entity* childEntity = CreateEntity("child", {component});
|
||||
|
||||
// Create a child prefab with an entity that has an Asset<T> reference on it
|
||||
childInstances.push_back(prefabSystemComponentInterface->CreatePrefab(
|
||||
{childEntity}, {}, ChildPrefabPath, AZStd::unique_ptr<AZ::Entity>(CreateEntity("Container"))));
|
||||
|
||||
// Create a parent prefab that has a nested instance reference to the child prefab
|
||||
auto parentInstance =
|
||||
prefabSystemComponentInterface->CreatePrefab({CreateEntity("parent")}, AZStd::move(childInstances), "parent.prefab", AZStd::unique_ptr<AZ::Entity>(CreateEntity("Container")));
|
||||
|
||||
AZStd::string serializedInstance;
|
||||
|
||||
TestPrefabBuilderComponent prefabBuilderComponent;
|
||||
prefabBuilderComponent.Activate();
|
||||
|
||||
AZStd::vector<AssetBuilderSDK::JobProduct> jobProducts;
|
||||
auto&& prefabDom = prefabSystemComponentInterface->FindTemplateDom(parentInstance->GetTemplateId());
|
||||
|
||||
ASSERT_TRUE(prefabBuilderComponent.ProcessPrefab({AZ::Crc32("pc")}, "parent.prefab", "unused", AZ::Uuid(), prefabDom, jobProducts));
|
||||
|
||||
ASSERT_EQ(jobProducts.size(), 1);
|
||||
ASSERT_EQ(jobProducts[0].m_dependencies.size(), 1);
|
||||
ASSERT_EQ(jobProducts[0].m_dependencies[0].m_dependencyId, TestAssetId);
|
||||
|
||||
prefabBuilderComponent.Deactivate();
|
||||
}
|
||||
|
||||
AZStd::pair<size_t, size_t> GetFingerprint(AzToolsFramework::Prefab::PrefabDom& dom)
|
||||
{
|
||||
TestPrefabBuilderComponent prefabBuilderComponent;
|
||||
|
||||
prefabBuilderComponent.Activate();
|
||||
size_t builderFingerprint = prefabBuilderComponent.CalculateBuilderFingerprint();
|
||||
size_t fingerprint = prefabBuilderComponent.CalculatePrefabFingerprint(dom);
|
||||
prefabBuilderComponent.Deactivate();
|
||||
|
||||
return {fingerprint, builderFingerprint};
|
||||
}
|
||||
|
||||
TEST_F(PrefabBuilderTests, FingerprintTest)
|
||||
{
|
||||
auto* prefabSystemComponentInterface = AZ::Interface<AzToolsFramework::Prefab::PrefabSystemComponentInterface>::Get();
|
||||
|
||||
ASSERT_NE(prefabSystemComponentInterface, nullptr);
|
||||
|
||||
auto* component = aznew TestComponent();
|
||||
AZ::Entity* entity = CreateEntity("test", {component});
|
||||
|
||||
auto parentInstance = prefabSystemComponentInterface->CreatePrefab(
|
||||
{entity}, {}, "test.prefab",
|
||||
AZStd::unique_ptr<AZ::Entity>(CreateEntity("Container")));
|
||||
|
||||
AZStd::vector<AssetBuilderSDK::JobProduct> jobProducts;
|
||||
auto&& prefabDom = prefabSystemComponentInterface->FindTemplateDom(parentInstance->GetTemplateId());
|
||||
|
||||
auto [v0Dom, v0Builder] = GetFingerprint(prefabDom);
|
||||
auto [sanityDom, sanityBuilder] = GetFingerprint(prefabDom);
|
||||
|
||||
// Make sure the fingerprint is stable without changes
|
||||
ASSERT_EQ(v0Dom, sanityDom);
|
||||
ASSERT_EQ(v0Builder, sanityBuilder);
|
||||
|
||||
AZ::SerializeContext* context = m_app.GetSerializeContext();
|
||||
|
||||
// Unreflect VersionChangingData, change its version, and reflect it again
|
||||
context->EnableRemoveReflection();
|
||||
VersionChangingData::Reflect(context);
|
||||
VersionChangingData::m_version = 1;
|
||||
context->DisableRemoveReflection();
|
||||
VersionChangingData::Reflect(context);
|
||||
|
||||
// Get the new fingerprint and check that it changed
|
||||
auto [v1Dom, v1Builder] = GetFingerprint(prefabDom);
|
||||
|
||||
ASSERT_NE(v0Dom, v1Dom); // Verify the fingerprint for the object changed
|
||||
ASSERT_NE(v0Builder, v1Builder); // Verify the fingerprint for the entire builder changed
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<AZ::IO::GenericStream> TestPrefabBuilderComponent::GetOutputStream(const AZ::IO::Path&) const
|
||||
{
|
||||
return AZStd::make_unique<SelfContainedMemoryStream>();
|
||||
}
|
||||
|
||||
void PrefabBuilderTests::SetUp()
|
||||
{
|
||||
AZ::ComponentApplication::Descriptor desc;
|
||||
m_app.Start(desc);
|
||||
m_app.CreateReflectionManager();
|
||||
|
||||
m_testComponentDescriptor = AZStd::unique_ptr<AZ::ComponentDescriptor>{TestComponent::CreateDescriptor()};
|
||||
m_testComponentDescriptor->Reflect(m_app.GetSerializeContext());
|
||||
TestAsset::Reflect(m_app.GetSerializeContext());
|
||||
VersionChangingData::Reflect(m_app.GetSerializeContext());
|
||||
|
||||
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
|
||||
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
|
||||
// in the unit tests.
|
||||
AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
|
||||
}
|
||||
|
||||
void PrefabBuilderTests::TearDown()
|
||||
{
|
||||
m_testComponentDescriptor = nullptr;
|
||||
|
||||
m_app.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV);
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <PrefabBuilderComponent.h>
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <Application/ToolsApplication.h>
|
||||
#include <AzCore/Component/ComponentApplication.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
struct VersionChangingData : AZ::Data::AssetData
|
||||
{
|
||||
AZ_TYPE_INFO(VersionChangingData, "{E3A37E19-AE61-4C2F-809E-03B4D83261E8}");
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<VersionChangingData>()->Version(m_version);
|
||||
}
|
||||
}
|
||||
|
||||
inline static int m_version = 0;
|
||||
};
|
||||
|
||||
struct TestAsset : AZ::Data::AssetData
|
||||
{
|
||||
AZ_TYPE_INFO(TestAsset, "{8E736462-5424-4720-A2D9-F71DFC5905E3}");
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<TestAsset>();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct TestComponent : AZ::Component
|
||||
{
|
||||
AZ_COMPONENT(TestComponent, "{E3982C6A-0B01-4B04-A3E2-D95729D4B9C6}");
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<TestComponent>()
|
||||
->Field("Asset", &TestComponent::m_asset)
|
||||
->Field("Version", &TestComponent::m_version);
|
||||
}
|
||||
}
|
||||
|
||||
void Activate() override
|
||||
{
|
||||
}
|
||||
void Deactivate() override
|
||||
{
|
||||
}
|
||||
|
||||
AZ::Data::Asset<TestAsset> m_asset{};
|
||||
VersionChangingData m_version;
|
||||
};
|
||||
|
||||
struct SelfContainedMemoryStream : AZ::IO::ByteContainerStream<AZStd::vector<char>>
|
||||
{
|
||||
SelfContainedMemoryStream() : ByteContainerStream<AZStd::vector<char>>{&m_bufferData}
|
||||
{
|
||||
}
|
||||
|
||||
AZStd::vector<char> m_bufferData;
|
||||
};
|
||||
|
||||
struct TestPrefabBuilderComponent : AZ::Prefab::PrefabBuilderComponent
|
||||
{
|
||||
protected:
|
||||
AZStd::unique_ptr<AZ::IO::GenericStream> GetOutputStream(const AZ::IO::Path& path) const override;
|
||||
};
|
||||
|
||||
struct PrefabBuilderTests : ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp() override;
|
||||
void TearDown() override;
|
||||
|
||||
AzToolsFramework::ToolsApplication m_app;
|
||||
AZStd::unique_ptr<AZ::ComponentDescriptor> m_testComponentDescriptor{};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"gem_name": "PrefabBuilder",
|
||||
"GemFormatVersion": 4,
|
||||
"Uuid": "88500802311C4793B03484BE2091B607",
|
||||
"Name": "PrefabBuilder",
|
||||
"DisplayName": "PrefabBuilder",
|
||||
"Version": "0.1.0",
|
||||
"Summary": "Asset Processor builder module for Prefabs",
|
||||
"Tags": ["Prefabs"],
|
||||
"IconPath": "preview.png",
|
||||
"Modules": [
|
||||
{
|
||||
"Name": "Editor",
|
||||
"Type": "EditorModule"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -10,5 +10,6 @@
|
||||
#
|
||||
|
||||
set(FILES
|
||||
PrefabBuilderModule.cpp
|
||||
PrefabBuilderComponent.h
|
||||
PrefabBuilderComponent.cpp
|
||||
)
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#
|
||||
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
# its licensors.
|
||||
#
|
||||
# For complete copyright and license terms please see the LICENSE at the root of this
|
||||
# distribution (the "License"). All use of this software is governed by the License,
|
||||
# or, if provided, by the license below or the license accompanying this file. Do not
|
||||
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
|
||||
set(FILES
|
||||
PrefabBuilderModule.cpp
|
||||
)
|
||||
@@ -0,0 +1,15 @@
|
||||
#
|
||||
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
# its licensors.
|
||||
#
|
||||
# For complete copyright and license terms please see the LICENSE at the root of this
|
||||
# distribution (the "License"). All use of this software is governed by the License,
|
||||
# or, if provided, by the license below or the license accompanying this file. Do not
|
||||
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
|
||||
set(FILES
|
||||
PrefabBuilderTests.h
|
||||
PrefabBuilderTests.cpp
|
||||
)
|
||||
Reference in New Issue
Block a user