You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
238 lines
8.6 KiB
C++
238 lines
8.6 KiB
C++
/*
|
|
* 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 <PrefabGroup/PrefabGroupBehavior.h>
|
|
#include <PrefabGroup/PrefabGroup.h>
|
|
#include <PrefabGroup/ProceduralAssetHandler.h>
|
|
#include <AzCore/Asset/AssetManagerBus.h>
|
|
#include <AzCore/IO/FileIO.h>
|
|
#include <AzCore/IO/Path/Path.h>
|
|
#include <AzCore/JSON/document.h>
|
|
#include <AzCore/JSON/error/en.h>
|
|
#include <AzCore/JSON/error/error.h>
|
|
#include <AzCore/JSON/prettywriter.h>
|
|
#include <AzCore/JSON/stringbuffer.h>
|
|
#include <AzCore/Serialization/SerializeContext.h>
|
|
#include <AzCore/std/smart_ptr/make_shared.h>
|
|
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
|
#include <AzToolsFramework/Prefab/PrefabLoaderInterface.h>
|
|
#include <AzToolsFramework/Prefab/PrefabSystemComponentInterface.h>
|
|
#include <AzToolsFramework/Prefab/Instance/InstanceToTemplateInterface.h>
|
|
#include <AzToolsFramework/Prefab/Procedural/ProceduralPrefabAsset.h>
|
|
#include <SceneAPI/SceneCore/Components/ExportingComponent.h>
|
|
#include <SceneAPI/SceneCore/Containers/Scene.h>
|
|
#include <SceneAPI/SceneCore/Containers/SceneManifest.h>
|
|
#include <SceneAPI/SceneCore/Events/ExportEventContext.h>
|
|
#include <SceneAPI/SceneCore/Events/ExportProductList.h>
|
|
#include <SceneAPI/SceneCore/Utilities/FileUtilities.h>
|
|
|
|
namespace AZ::SceneAPI::Behaviors
|
|
{
|
|
//
|
|
// ExportEventHandler
|
|
//
|
|
|
|
struct PrefabGroupBehavior::ExportEventHandler final
|
|
: public AZ::SceneAPI::SceneCore::ExportingComponent
|
|
{
|
|
using PreExportEventContextFunction = AZStd::function<Events::ProcessingResult(Events::PreExportEventContext&)>;
|
|
PreExportEventContextFunction m_preExportEventContextFunction;
|
|
AZ::Prefab::PrefabGroupAssetHandler m_prefabGroupAssetHandler;
|
|
|
|
ExportEventHandler() = delete;
|
|
|
|
ExportEventHandler(PreExportEventContextFunction function)
|
|
: m_preExportEventContextFunction(AZStd::move(function))
|
|
{
|
|
BindToCall(&ExportEventHandler::PrepareForExport);
|
|
AZ::SceneAPI::SceneCore::ExportingComponent::Activate();
|
|
}
|
|
|
|
~ExportEventHandler()
|
|
{
|
|
AZ::SceneAPI::SceneCore::ExportingComponent::Deactivate();
|
|
}
|
|
|
|
Events::ProcessingResult PrepareForExport(Events::PreExportEventContext& context)
|
|
{
|
|
return m_preExportEventContextFunction(context);
|
|
}
|
|
};
|
|
|
|
//
|
|
// PrefabGroupBehavior
|
|
//
|
|
|
|
void PrefabGroupBehavior::Activate()
|
|
{
|
|
m_exportEventHandler = AZStd::make_shared<ExportEventHandler>([this](auto& context)
|
|
{
|
|
return this->OnPrepareForExport(context);
|
|
});
|
|
}
|
|
|
|
void PrefabGroupBehavior::Deactivate()
|
|
{
|
|
m_exportEventHandler.reset();
|
|
}
|
|
|
|
AZStd::unique_ptr<rapidjson::Document> PrefabGroupBehavior::CreateProductAssetData(const SceneData::PrefabGroup* prefabGroup) const
|
|
{
|
|
using namespace AzToolsFramework::Prefab;
|
|
|
|
auto* prefabLoaderInterface = AZ::Interface<PrefabLoaderInterface>::Get();
|
|
if (!prefabLoaderInterface)
|
|
{
|
|
AZ_Error("prefab", false, "Could not get PrefabLoaderInterface");
|
|
return {};
|
|
}
|
|
|
|
// write to a UTF-8 string buffer
|
|
auto prefabDomRef = prefabGroup->GetPrefabDomRef();
|
|
if (!prefabDomRef)
|
|
{
|
|
AZ_Error("prefab", false, "PrefabGroup(%s) missing PrefabDom", prefabGroup->GetName().c_str());
|
|
return {};
|
|
}
|
|
|
|
const AzToolsFramework::Prefab::PrefabDom& prefabDom = prefabDomRef.value();
|
|
rapidjson::StringBuffer sb;
|
|
rapidjson::Writer<rapidjson::StringBuffer, rapidjson::UTF8<>> writer(sb);
|
|
if (prefabDom.Accept(writer) == false)
|
|
{
|
|
AZ_Error("prefab", false, "Could not write PrefabGroup(%s) to JSON", prefabGroup->GetName().c_str());
|
|
return {};
|
|
}
|
|
|
|
// validate the PrefabDom will make a valid Prefab template instance
|
|
auto templateId = prefabLoaderInterface->LoadTemplateFromString(sb.GetString(), prefabGroup->GetName().c_str());
|
|
if (templateId == InvalidTemplateId)
|
|
{
|
|
AZ_Error("prefab", false, "PrefabGroup(%s) Could not write load template", prefabGroup->GetName().c_str());
|
|
return {};
|
|
}
|
|
|
|
auto* prefabSystemComponentInterface = AZ::Interface<PrefabSystemComponentInterface>::Get();
|
|
if (!prefabSystemComponentInterface)
|
|
{
|
|
AZ_Error("prefab", false, "Could not get PrefabSystemComponentInterface");
|
|
return {};
|
|
}
|
|
|
|
const rapidjson::Document& generatedInstanceDom = prefabSystemComponentInterface->FindTemplateDom(templateId);
|
|
auto proceduralPrefab = AZStd::make_unique<rapidjson::Document>(rapidjson::kObjectType);
|
|
proceduralPrefab->CopyFrom(generatedInstanceDom, proceduralPrefab->GetAllocator(), true);
|
|
|
|
return proceduralPrefab;
|
|
}
|
|
|
|
bool PrefabGroupBehavior::WriteOutProductAsset(
|
|
Events::PreExportEventContext& context,
|
|
const SceneData::PrefabGroup* prefabGroup,
|
|
const rapidjson::Document& doc) const
|
|
{
|
|
// Retrieve source asset info so we can get a string with the relative path to the asset
|
|
bool assetInfoResult;
|
|
Data::AssetInfo info;
|
|
AZStd::string watchFolder;
|
|
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
|
|
assetInfoResult,
|
|
&AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath,
|
|
context.GetScene().GetSourceFilename().c_str(),
|
|
info,
|
|
watchFolder);
|
|
|
|
AZ::IO::FixedMaxPath assetPath(info.m_relativePath);
|
|
assetPath.ReplaceFilename(prefabGroup->GetName().c_str());
|
|
|
|
AZStd::string filePath = AZ::SceneAPI::Utilities::FileUtilities::CreateOutputFileName(
|
|
assetPath.c_str(),
|
|
context.GetOutputDirectory(),
|
|
AZ::Prefab::PrefabGroupAssetHandler::s_Extension);
|
|
|
|
AZ::IO::FileIOStream fileStream(filePath.c_str(), AZ::IO::OpenMode::ModeWrite);
|
|
if (fileStream.IsOpen() == false)
|
|
{
|
|
AZ_Error("prefab", false, "File path(%s) could not open for write", filePath.c_str());
|
|
return false;
|
|
}
|
|
|
|
// write to a UTF-8 string buffer
|
|
rapidjson::StringBuffer sb;
|
|
rapidjson::Writer<rapidjson::StringBuffer, rapidjson::UTF8<>> writer(sb);
|
|
if (doc.Accept(writer) == false)
|
|
{
|
|
AZ_Error("prefab", false, "PrefabGroup(%s) Could not buffer JSON", prefabGroup->GetName().c_str());
|
|
return false;
|
|
}
|
|
|
|
const auto bytesWritten = fileStream.Write(sb.GetSize(), sb.GetString());
|
|
if (bytesWritten > 1)
|
|
{
|
|
AZ::u32 subId = AZ::Crc32(assetPath.c_str());
|
|
context.GetProductList().AddProduct(
|
|
filePath,
|
|
context.GetScene().GetSourceGuid(),
|
|
azrtti_typeid<Prefab::ProceduralPrefabAsset>(),
|
|
{},
|
|
AZStd::make_optional(subId));
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Events::ProcessingResult PrefabGroupBehavior::OnPrepareForExport(Events::PreExportEventContext& context) const
|
|
{
|
|
AZStd::vector<const SceneData::PrefabGroup*> prefabGroupCollection;
|
|
const Containers::SceneManifest& manifest = context.GetScene().GetManifest();
|
|
|
|
for (size_t i = 0; i < manifest.GetEntryCount(); ++i)
|
|
{
|
|
const auto* group = azrtti_cast<const SceneData::PrefabGroup*>(manifest.GetValue(i).get());
|
|
if (group)
|
|
{
|
|
prefabGroupCollection.push_back(group);
|
|
}
|
|
}
|
|
|
|
if (prefabGroupCollection.empty())
|
|
{
|
|
return AZ::SceneAPI::Events::ProcessingResult::Ignored;
|
|
}
|
|
|
|
for (const auto* prefabGroup : prefabGroupCollection)
|
|
{
|
|
auto result = CreateProductAssetData(prefabGroup);
|
|
if (!result)
|
|
{
|
|
return Events::ProcessingResult::Failure;
|
|
}
|
|
|
|
if (WriteOutProductAsset(context, prefabGroup, *result.get()) == false)
|
|
{
|
|
return Events::ProcessingResult::Failure;
|
|
}
|
|
}
|
|
|
|
return Events::ProcessingResult::Success;
|
|
}
|
|
|
|
void PrefabGroupBehavior::Reflect(ReflectContext* context)
|
|
{
|
|
AZ::SceneAPI::SceneData::PrefabGroup::Reflect(context);
|
|
Prefab::ProceduralPrefabAsset::Reflect(context);
|
|
|
|
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
|
|
if (serializeContext)
|
|
{
|
|
serializeContext->Class<PrefabGroupBehavior, BehaviorComponent>()->Version(1);
|
|
}
|
|
}
|
|
}
|