Files
UnrealEngineUWP/Engine/Plugins/Runtime/Metasound/Source/MetasoundEngine/Public/MetasoundDocumentBuilderRegistry.h
AdricEpic 0976464d97 #1 Pages Checkpoint: Update BuilderAPI, associated delegates to support providing Pages
#rb helen.yang, phil.popp
#rnx
#jira UE-194160

[CL 34477958 by AdricEpic in ue5-main branch]
2024-06-18 16:47:21 -04:00

136 lines
6.0 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Algo/Find.h"
#include "Async/Async.h"
#include "MetasoundBuilderBase.h"
#include "MetasoundDocumentInterface.h"
#include "MetasoundFrontendDocument.h"
#include "MetasoundFrontendRegistries.h"
#include "MetasoundLog.h"
#include "Misc/ScopeLock.h"
namespace Metasound::Engine
{
class METASOUNDENGINE_API FDocumentBuilderRegistry : public Frontend::IDocumentBuilderRegistry
{
mutable TMultiMap<FMetasoundFrontendClassName, TWeakObjectPtr<UMetaSoundBuilderBase>> Builders;
// Critical section primarily for allowing builder collection mutation during async loading of MetaSound assets.
mutable FCriticalSection BuildersCriticalSection;
public:
FDocumentBuilderRegistry() = default;
virtual ~FDocumentBuilderRegistry();
static FDocumentBuilderRegistry& GetChecked()
{
return static_cast<FDocumentBuilderRegistry&>(IDocumentBuilderRegistry::GetChecked());
}
enum class ELogEvent : uint8
{
DuplicateEntries
};
template <typename BuilderClass>
BuilderClass& CreateTransientBuilder(FName BuilderName = FName())
{
using namespace Metasound::Frontend;
checkf(IsInGameThread(), TEXT("Transient MetaSound builder cannot be created in non - game thread as it may result in UObject creation"));
const EObjectFlags NewObjectFlags = RF_Public | RF_Transient;
UPackage* TransientPackage = GetTransientPackage();
const FName ObjectName = MakeUniqueObjectName(TransientPackage, BuilderClass::StaticClass(), BuilderName);
TObjectPtr<BuilderClass> NewBuilder = NewObject<BuilderClass>(TransientPackage, ObjectName, NewObjectFlags);
check(NewBuilder);
NewBuilder->Initialize();
const FMetasoundFrontendDocument& Document = NewBuilder->GetConstBuilder().GetConstDocumentChecked();
const FMetasoundFrontendClassName& ClassName = Document.RootGraph.Metadata.GetClassName();
Builders.Add(ClassName, NewBuilder);
return *NewBuilder.Get();
}
#if WITH_EDITORONLY_DATA
template <typename BuilderClass = UMetaSoundBuilderBase>
BuilderClass& FindOrBeginBuilding(UObject& InMetaSoundObject) const
{
check(InMetaSoundObject.IsAsset());
TScriptInterface<IMetaSoundDocumentInterface> DocInterface = &InMetaSoundObject;
check(DocInterface.GetObject());
if (UMetaSoundBuilderBase* Builder = FindBuilderObject(&InMetaSoundObject))
{
return *CastChecked<BuilderClass>(Builder);
}
FNameBuilder BuilderName;
BuilderName.Append(InMetaSoundObject.GetName());
BuilderName.Append(TEXT("_Builder"));
const UClass& BuilderUClass = DocInterface->GetBuilderUClass();
const FName NewName = MakeUniqueObjectName(nullptr, &BuilderUClass, FName(*BuilderName));
TObjectPtr<UMetaSoundBuilderBase> NewBuilder;
{
FScopeLock Lock(&BuildersCriticalSection);
NewBuilder = CastChecked<UMetaSoundBuilderBase>(NewObject<UObject>(&InMetaSoundObject, &BuilderUClass, NewName));
FMetaSoundFrontendDocumentBuilder& BuilderRef = NewBuilder->GetBuilder();
BuilderRef = FMetaSoundFrontendDocumentBuilder(DocInterface);
const FMetasoundFrontendDocument& Document = DocInterface->GetConstDocument();
const FMetasoundFrontendClassName& ClassName = Document.RootGraph.Metadata.GetClassName();
if (!ClassName.IsValid())
{
BuilderRef.InitDocument();
}
checkf(ClassName.IsValid(), TEXT("Document initialization must result in a valid class name being generated"));
AddBuilderInternal(ClassName, NewBuilder);
}
return *CastChecked<BuilderClass>(NewBuilder);
}
#endif // WITH_EDITORONLY_DATA
// Frontend::IDocumentBuilderRegistry Implementation
#if WITH_EDITORONLY_DATA
virtual FMetaSoundFrontendDocumentBuilder& FindOrBeginBuilding(TScriptInterface<IMetaSoundDocumentInterface> MetaSound) override;
#endif // WITH_EDITORONLY_DATA
virtual FMetaSoundFrontendDocumentBuilder* FindBuilder(TScriptInterface<IMetaSoundDocumentInterface> MetaSound) const override;
virtual FMetaSoundFrontendDocumentBuilder* FindBuilder(const FMetasoundFrontendClassName& InClassName, const FTopLevelAssetPath& AssetPath) const override;
virtual FMetaSoundFrontendDocumentBuilder* FindOutermostBuilder(const UObject& InSubObject) const override;
virtual bool FinishBuilding(const FMetasoundFrontendClassName& InClassName, bool bForceUnregisterNodeClass = false) const override;
virtual bool FinishBuilding(const FMetasoundFrontendClassName& InClassName, const FTopLevelAssetPath& AssetPath, bool bForceUnregisterNodeClass = false) const override;
// Returns the builder object associated with the given MetaSound asset if one is registered and active.
UMetaSoundBuilderBase* FindBuilderObject(TScriptInterface<const IMetaSoundDocumentInterface> MetaSound) const;
// Returns the builder object associated with the given ClassName if one is registered and active.
// Optionally, if provided the AssetPath and there is a conflict (i.e. more than one asset is registered
// with a given ClassName), will return the one with the provided AssetPath. Otherwise, will arbitrarily
// return one.
UMetaSoundBuilderBase* FindBuilderObject(const FMetasoundFrontendClassName& InClassName, const FTopLevelAssetPath& AssetPath) const;
// Returns all builder objects registered and active associated with the given ClassName.
TArray<UMetaSoundBuilderBase*> FindBuilderObjects(const FMetasoundFrontendClassName& InClassName) const;
// Given the provided document, returns the valid page ID to be executed.
virtual FGuid ResolveExecutablePageID(const TScriptInterface<IMetaSoundDocumentInterface> DocumentInterface) const;
bool ReloadBuilder(const FMetasoundFrontendClassName& InClassName) const override;
void SetEventLogVerbosity(ELogEvent Event, ELogVerbosity::Type Verbosity);
private:
void AddBuilderInternal(const FMetasoundFrontendClassName& InClassName, UMetaSoundBuilderBase* NewBuilder) const;
bool CanPostEventLog(ELogEvent Event, ELogVerbosity::Type Verbosity) const;
void FinishBuildingInternal(UMetaSoundBuilderBase& Builder, bool bForceUnregisterNodeClass) const;
TSortedMap<ELogEvent, ELogVerbosity::Type> EventLogVerbosity;
};
} // namespace Metasound::Engine