/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace AZ { namespace SceneAPI { namespace Events { struct UpdateManifestScope final : public AssetImportRequestReporter { AZ_RTTI(UpdateManifestScope, "{C9DD605E-2A9D-4C0D-A22E-A71B44528420}", AssetImportRequestReporter); UpdateManifestScope(AZStd::shared_ptr scene) : m_scene(scene) { m_registered = false; if (AZ::SettingsRegistry::Get()) { AZ::SettingsRegistry::Get()->Get(m_registered, AZ::SceneAPI::Utilities::Key_AssetProcessorInDebugOutput); } if (m_registered) { AZ::Interface::Register(this); } } ~UpdateManifestScope() { if (m_registered) { AZ::Interface::Unregister(this); m_registered = false; } m_previousManifest = {}; } void ReportStart([[maybe_unused]] const AssetImportRequest* instance) override { ++m_reportNumber; if (m_previousManifest.IsEmpty() && !m_scene->GetManifest().IsEmpty()) { m_previousManifest = m_scene->GetManifest(); } } void ReportFinish(const AssetImportRequest* instance) override { AZStd::string policy; instance->GetPolicyName(policy); AZ_TraceContext("PolicyName", policy.c_str()); if (ManifestInstancesAreEqual(m_previousManifest, m_scene->GetManifest())) { AZ_TracePrintf(AZ::SceneAPI::Utilities::LogWindow, "UpdateManifest(%d): No Changes \n", m_reportNumber); } else { AZ_TraceContext("Old manifest rule count", aznumeric_cast(m_previousManifest.GetEntryCount())); AZ_TraceContext("New manifest rule count", aznumeric_cast(m_scene->GetManifest().GetEntryCount())); AZ_TracePrintf(AZ::SceneAPI::Utilities::LogWindow, "UpdateManifest(%d): Updated \n", m_reportNumber); m_previousManifest = m_scene->GetManifest(); } } bool ManifestInstancesAreEqual(const Containers::SceneManifest& lhs, const Containers::SceneManifest& rhs) const { if (lhs.IsEmpty() && rhs.IsEmpty()) { return true; } if (lhs.GetEntryCount() == rhs.GetEntryCount()) { auto rhsValueStorage = rhs.GetValueStorage(); for (auto index = 0; index < lhs.GetEntryCount(); ++index) { const auto lhsObject = lhs.GetValue(index); auto found = AZStd::find_if(rhsValueStorage.begin(), rhsValueStorage.end(), [lhsObject](const auto& rhs) { return lhsObject.get()->RTTI_Type() == rhs.get()->RTTI_Type(); }); if (found == rhsValueStorage.end()) { return false; } } return true; } return false; } AZStd::shared_ptr m_scene; AZ::s32 m_reportNumber = 0; bool m_registered = false; Containers::SceneManifest m_previousManifest; }; // an internal scope object that is active during a scene import struct ImportScope final : public AZ::SceneAPI::Events::AssetPostImportRequestBus::Handler { ImportScope() { AZ::SceneAPI::Events::AssetPostImportRequestBus::Handler::BusConnect(); } ~ImportScope() { AZ::SceneAPI::Events::AssetPostImportRequestBus::ExecuteQueuedEvents(); AZ::SceneAPI::Events::AssetPostImportRequestBus::Handler::BusDisconnect(); } void CallAfterSceneExport(AZStd::function callback) override { callback(); } }; // // Loading Result Combiner // LoadingResultCombiner::LoadingResultCombiner() : m_manifestResult(ProcessingResult::Ignored) , m_assetResult(ProcessingResult::Ignored) { } void LoadingResultCombiner::operator=(LoadingResult rhs) { switch (rhs) { case LoadingResult::Ignored: return; case LoadingResult::AssetLoaded: m_assetResult = m_assetResult != ProcessingResult::Failure ? ProcessingResult::Success : ProcessingResult::Failure; return; case LoadingResult::ManifestLoaded: m_manifestResult = m_manifestResult != ProcessingResult::Failure ? ProcessingResult::Success : ProcessingResult::Failure; return; case LoadingResult::AssetFailure: m_assetResult = ProcessingResult::Failure; return; case LoadingResult::ManifestFailure: m_manifestResult = ProcessingResult::Failure; return; } } ProcessingResult LoadingResultCombiner::GetManifestResult() const { return m_manifestResult; } ProcessingResult LoadingResultCombiner::GetAssetResult() const { return m_assetResult; } // // Asset Importer Request // void AssetImportRequest::GetManifestExtension(AZStd::string& /*result*/) { } void AssetImportRequest::GetGeneratedManifestExtension(AZStd::string& /*result*/) { } void AssetImportRequest::GetPolicyName(AZStd::string& result) const { result = "AssetImportRequest Base"; } void AssetImportRequest::GetSupportedFileExtensions(AZStd::unordered_set& /*extensions*/) { } ProcessingResult AssetImportRequest::PrepareForAssetLoading(Containers::Scene& /*scene*/, RequestingApplication /*requester*/) { return ProcessingResult::Ignored; } LoadingResult AssetImportRequest::LoadAsset(Containers::Scene& /*scene*/, const AZStd::string& /*path*/, const Uuid& /*guid*/, RequestingApplication /*requester*/) { return LoadingResult::Ignored; } void AssetImportRequest::FinalizeAssetLoading(Containers::Scene& /*scene*/, RequestingApplication /*requester*/) { } ProcessingResult AssetImportRequest::UpdateManifest(Containers::Scene& /*scene*/, ManifestAction /*action*/, RequestingApplication /*requester*/) { return ProcessingResult::Ignored; } void AssetImportRequest::AreCustomNormalsUsed(bool &value) { // Leave the SceneProcessingConfigSystemComponent do the job AZ_UNUSED(value); } void AssetImportRequest::GetManifestDependencyPaths(AZStd::vector&) { } AZStd::shared_ptr AssetImportRequest::LoadSceneFromVerifiedPath( const AZStd::string& assetFilePath, const Uuid& sourceGuid, RequestingApplication requester, const Uuid& loadingComponentUuid, const AZStd::string& watchFolder) { ImportScope importScope; AZStd::string sceneName; AzFramework::StringFunc::Path::GetFileName(assetFilePath.c_str(), sceneName); AZStd::shared_ptr scene = AZStd::make_shared(AZStd::move(sceneName)); AZ_Assert(scene, "Unable to create new scene for asset importing."); Data::AssetInfo assetInfo; AZStd::string watchFolderFromDatabase; bool result = false; AzToolsFramework::AssetSystemRequestBus::BroadcastResult(result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourceUUID, sourceGuid, assetInfo, watchFolderFromDatabase); if (result) { scene->SetWatchFolder(watchFolderFromDatabase); } else { scene->SetWatchFolder(watchFolder); AZ_Warning( "AssetImportRequest", false, "Failed to get watch folder for source %s", sourceGuid.ToString().c_str()); } // Unique pointer, will deactivate and clean up once going out of scope. SceneCore::EntityConstructor::EntityPointer loaders = SceneCore::EntityConstructor::BuildEntity("Scene Loading", loadingComponentUuid); ProcessingResultCombiner areAllPrepared; AssetImportRequestBus::BroadcastResult(areAllPrepared, &AssetImportRequestBus::Events::PrepareForAssetLoading, *scene, requester); if (areAllPrepared.GetResult() == ProcessingResult::Failure) { AZ_TracePrintf(Utilities::ErrorWindow, "Not all asset loaders could initialize.\n"); return nullptr; } LoadingResultCombiner filesLoaded; AssetImportRequestBus::BroadcastResult(filesLoaded, &AssetImportRequestBus::Events::LoadAsset, *scene, assetFilePath, sourceGuid, requester); AssetImportRequestBus::Broadcast(&AssetImportRequestBus::Events::FinalizeAssetLoading, *scene, requester); if (filesLoaded.GetAssetResult() != ProcessingResult::Success) { AZ_TracePrintf(Utilities::ErrorWindow, "Failed to load requested scene file.\n"); return nullptr; } ManifestAction action = ManifestAction::Update; // If the result for manifest is ignored it means no manifest was found or it was empty. if (filesLoaded.GetManifestResult() == ProcessingResult::Failure || filesLoaded.GetManifestResult() == ProcessingResult::Ignored || scene->GetManifest().IsEmpty()) { scene->GetManifest().Clear(); action = ManifestAction::ConstructDefault; } UpdateManifestScope updateManifestScope(scene); ProcessingResultCombiner manifestUpdate; AssetImportRequestBus::BroadcastResult(manifestUpdate, &AssetImportRequestBus::Events::UpdateManifest, *scene, action, requester); if (manifestUpdate.GetResult() == ProcessingResult::Failure) { AZ_TracePrintf(Utilities::ErrorWindow, "Unable to %s manifest.\n", action == ManifestAction::ConstructDefault ? "create new" : "update"); return nullptr; } return scene; } bool AssetImportRequest::IsManifestExtension(const char* filePath) { AZStd::string manifestExtension; AssetImportRequestBus::Broadcast(&AssetImportRequestBus::Events::GetManifestExtension, manifestExtension); AZ_Assert(!manifestExtension.empty(), "Manifest extension was not declared."); return AzFramework::StringFunc::Path::IsExtension(filePath, manifestExtension.c_str()); } bool AssetImportRequest::IsSceneFileExtension(const char* filePath) { AZStd::unordered_set extensions; AssetImportRequestBus::Broadcast(&AssetImportRequestBus::Events::GetSupportedFileExtensions, extensions); AZ_Assert(!extensions.empty(), "No extensions found for source files."); for (const AZStd::string& extension : extensions) { if (AzFramework::StringFunc::Path::IsExtension(filePath, extension.c_str())) { return true; } } return false; } } // namespace Events } // namespace SceneAPI } // namespace AZ