123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- /*
- * 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 {};
- }
- // create instance to update the asset hints
- auto instance = prefabSystemComponentInterface->InstantiatePrefab(templateId);
- if (!instance)
- {
- AZ_Error("prefab", false, "PrefabGroup(%s) Could not instantiate prefab", prefabGroup->GetName().c_str());
- return {};
- }
- auto* instanceToTemplateInterface = AZ::Interface<InstanceToTemplateInterface>::Get();
- if (!instanceToTemplateInterface)
- {
- AZ_Error("prefab", false, "Could not get InstanceToTemplateInterface");
- return {};
- }
- // fill out a JSON DOM
- auto proceduralPrefab = AZStd::make_unique<rapidjson::Document>(rapidjson::kObjectType);
- instanceToTemplateInterface->GenerateDomForInstance(*proceduralPrefab.get(), *instance.get());
- 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(filePath.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);
- }
- }
- }
|