2021-10-12 21:21:22 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "MetasoundFrontendDocumentController.h"
# include "Algo/ForEach.h"
# include "HAL/FileManager.h"
# include "MetasoundFrontendGraphController.h"
2023-06-20 13:12:39 -04:00
# include "MetasoundFrontendDocumentIdGenerator.h"
2021-10-12 21:21:22 -04:00
# include "MetasoundFrontendInvalidController.h"
# include "MetasoundJsonBackend.h"
# include "StructSerializer.h"
# define LOCTEXT_NAMESPACE "MetasoundFrontendDocumentController"
namespace Metasound
{
namespace Frontend
{
//
// FDocumentController
//
FDocumentController : : FDocumentController ( FDocumentAccessPtr InDocumentPtr )
: DocumentPtr ( InDocumentPtr )
{
}
bool FDocumentController : : IsValid ( ) const
{
return ( nullptr ! = DocumentPtr . Get ( ) ) ;
}
const TArray < FMetasoundFrontendClass > & FDocumentController : : GetDependencies ( ) const
{
if ( const FMetasoundFrontendDocument * Document = DocumentPtr . Get ( ) )
{
return Document - > Dependencies ;
}
return Invalid : : GetInvalidClassArray ( ) ;
}
2022-01-26 18:11:52 -05:00
void FDocumentController : : IterateDependencies ( TFunctionRef < void ( FMetasoundFrontendClass & ) > InFunction )
{
if ( FMetasoundFrontendDocument * Document = DocumentPtr . Get ( ) )
{
Algo : : ForEach ( Document - > Dependencies , InFunction ) ;
}
}
void FDocumentController : : IterateDependencies ( TFunctionRef < void ( const FMetasoundFrontendClass & ) > InFunction ) const
{
if ( const FMetasoundFrontendDocument * Document = DocumentPtr . Get ( ) )
{
Algo : : ForEach ( Document - > Dependencies , InFunction ) ;
}
}
2021-10-12 21:21:22 -04:00
const TArray < FMetasoundFrontendGraphClass > & FDocumentController : : GetSubgraphs ( ) const
{
if ( const FMetasoundFrontendDocument * Document = DocumentPtr . Get ( ) )
{
return Document - > Subgraphs ;
}
return Invalid : : GetInvalidGraphClassArray ( ) ;
}
const FMetasoundFrontendGraphClass & FDocumentController : : GetRootGraphClass ( ) const
{
if ( const FMetasoundFrontendDocument * Doc = DocumentPtr . Get ( ) )
{
return Doc - > RootGraph ;
}
return Invalid : : GetInvalidGraphClass ( ) ;
}
2022-01-26 18:11:52 -05:00
void FDocumentController : : SetRootGraphClass ( FMetasoundFrontendGraphClass & & InClass )
{
if ( FMetasoundFrontendDocument * Doc = DocumentPtr . Get ( ) )
{
Doc - > RootGraph = MoveTemp ( InClass ) ;
}
}
2021-10-12 21:21:22 -04:00
bool FDocumentController : : AddDuplicateSubgraph ( const FMetasoundFrontendGraphClass & InGraphToCopy , const FMetasoundFrontendDocument & InOtherDocument )
{
if ( FMetasoundFrontendDocument * Document = DocumentPtr . Get ( ) )
{
// Direct copy of subgraph
bool bSuccess = true ;
FMetasoundFrontendGraphClass SubgraphCopy ( InGraphToCopy ) ;
for ( FMetasoundFrontendNode & Node : SubgraphCopy . Graph . Nodes )
{
const FGuid OriginalClassID = Node . ClassID ;
auto IsClassWithClassID = [ & ] ( const FMetasoundFrontendClass & InClass ) - > bool
{
return InClass . ID = = OriginalClassID ;
} ;
if ( const FMetasoundFrontendClass * OriginalNodeClass = InOtherDocument . Dependencies . FindByPredicate ( IsClassWithClassID ) )
{
// Should not be a graph class since it's in the dependencies list
check ( EMetasoundFrontendClassType : : Graph ! = OriginalNodeClass - > Metadata . GetType ( ) ) ;
if ( const FMetasoundFrontendClass * NodeClass = FindOrAddClass ( OriginalNodeClass - > Metadata ) . Get ( ) )
{
// All this just to update this ID. Maybe having globally
// consistent class IDs would help. Or using the classname & version as
// a class ID.
Node . ClassID = NodeClass - > ID ;
}
else
{
UE_LOG ( LogMetaSound , Error , TEXT ( " Failed to add subgraph dependency [Class:%s] " ) , * OriginalNodeClass - > Metadata . GetClassName ( ) . ToString ( ) ) ;
bSuccess = false ;
}
}
else if ( const FMetasoundFrontendGraphClass * OriginalNodeGraphClass = InOtherDocument . Subgraphs . FindByPredicate ( IsClassWithClassID ) )
{
bSuccess = bSuccess & & AddDuplicateSubgraph ( * OriginalNodeGraphClass , InOtherDocument ) ;
if ( ! bSuccess )
{
break ;
}
}
else
{
bSuccess = false ;
UE_LOG ( LogMetaSound , Error , TEXT ( " Failed to copy subgraph. Subgraph document is missing dependency info for node [Node:%s, NodeID:%s] " ) , * Node . Name . ToString ( ) , * Node . GetID ( ) . ToString ( ) ) ;
}
}
if ( bSuccess )
{
Document - > Subgraphs . Add ( SubgraphCopy ) ;
}
return bSuccess ;
}
return false ;
}
2021-12-10 20:37:31 -05:00
const TSet < FMetasoundFrontendVersion > & FDocumentController : : GetInterfaceVersions ( ) const
2021-10-12 21:21:22 -04:00
{
if ( const FMetasoundFrontendDocument * Doc = DocumentPtr . Get ( ) )
{
2021-12-10 20:37:31 -05:00
return Doc - > Interfaces ;
2021-10-12 21:21:22 -04:00
}
2021-11-22 15:55:50 -05:00
2021-12-10 20:37:31 -05:00
static const TSet < FMetasoundFrontendVersion > EmptySet ;
return EmptySet ;
2021-10-12 21:21:22 -04:00
}
2021-11-22 15:55:50 -05:00
void FDocumentController : : AddInterfaceVersion ( const FMetasoundFrontendVersion & InVersion )
2021-10-12 21:21:22 -04:00
{
if ( FMetasoundFrontendDocument * Doc = DocumentPtr . Get ( ) )
{
2022-09-22 15:02:24 -04:00
# if WITH_EDITOR
2023-05-08 19:08:22 -04:00
Doc - > Metadata . ModifyContext . AddInterfaceModified ( InVersion . Name ) ;
2022-09-22 15:02:24 -04:00
# endif // WITH_EDITOR
2021-12-10 20:37:31 -05:00
Doc - > Interfaces . Add ( InVersion ) ;
2021-11-22 15:55:50 -05:00
}
}
void FDocumentController : : RemoveInterfaceVersion ( const FMetasoundFrontendVersion & InVersion )
{
if ( FMetasoundFrontendDocument * Doc = DocumentPtr . Get ( ) )
{
2022-09-22 15:02:24 -04:00
# if WITH_EDITOR
2023-05-08 19:08:22 -04:00
Doc - > Metadata . ModifyContext . AddInterfaceModified ( InVersion . Name ) ;
2022-09-22 15:02:24 -04:00
# endif // WITH_EDITOR
2021-12-10 20:37:31 -05:00
Doc - > Interfaces . Remove ( InVersion ) ;
2021-11-22 15:55:50 -05:00
}
}
void FDocumentController : : ClearInterfaceVersions ( )
{
if ( FMetasoundFrontendDocument * Doc = DocumentPtr . Get ( ) )
{
2021-12-10 20:37:31 -05:00
Doc - > Interfaces . Reset ( ) ;
2021-10-12 21:21:22 -04:00
}
}
FGraphHandle FDocumentController : : AddDuplicateSubgraph ( const IGraphController & InGraph )
{
// TODO: class IDs have issues..
// Currently ClassIDs are just used for internal linking. They need to be fixed up
// here if swapping documents. In the future, ClassIDs should be unique and consistent
// across documents and platforms.
FConstDocumentAccess GraphDocumentAccess = GetSharedAccess ( * InGraph . GetOwningDocument ( ) ) ;
const FMetasoundFrontendDocument * OtherDocument = GraphDocumentAccess . ConstDocument . Get ( ) ;
if ( nullptr = = OtherDocument )
{
UE_LOG ( LogMetaSound , Error , TEXT ( " Cannot add subgraph from invalid document " ) ) ;
return IGraphController : : GetInvalidHandle ( ) ;
}
FConstDocumentAccess GraphAccess = GetSharedAccess ( InGraph ) ;
const FMetasoundFrontendGraphClass * OtherGraph = GraphAccess . ConstGraphClass . Get ( ) ;
if ( nullptr = = OtherGraph )
{
UE_LOG ( LogMetaSound , Error , TEXT ( " Cannot add invalid subgraph to document " ) ) ;
return IGraphController : : GetInvalidHandle ( ) ;
}
if ( AddDuplicateSubgraph ( * OtherGraph , * OtherDocument ) )
{
if ( const FMetasoundFrontendClass * SubgraphClass = FindClass ( OtherGraph - > Metadata ) . Get ( ) )
{
return GetSubgraphWithClassID ( SubgraphClass - > ID ) ;
}
}
return IGraphController : : GetInvalidHandle ( ) ;
}
FConstClassAccessPtr FDocumentController : : FindDependencyWithID ( FGuid InClassID ) const
{
return DocumentPtr . GetDependencyWithID ( InClassID ) ;
}
FConstGraphClassAccessPtr FDocumentController : : FindSubgraphWithID ( FGuid InClassID ) const
{
return DocumentPtr . GetSubgraphWithID ( InClassID ) ;
}
FConstClassAccessPtr FDocumentController : : FindClassWithID ( FGuid InClassID ) const
{
FConstClassAccessPtr MetasoundClass = FindDependencyWithID ( InClassID ) ;
if ( nullptr = = MetasoundClass . Get ( ) )
{
MetasoundClass = FindSubgraphWithID ( InClassID ) ;
}
return MetasoundClass ;
}
void FDocumentController : : SetMetadata ( const FMetasoundFrontendDocumentMetadata & InMetadata )
{
if ( FMetasoundFrontendDocument * Document = DocumentPtr . Get ( ) )
{
Document - > Metadata = InMetadata ;
}
}
const FMetasoundFrontendDocumentMetadata & FDocumentController : : GetMetadata ( ) const
{
if ( const FMetasoundFrontendDocument * Document = DocumentPtr . Get ( ) )
{
return Document - > Metadata ;
}
return Invalid : : GetInvalidDocumentMetadata ( ) ;
}
2022-09-22 15:02:24 -04:00
FMetasoundFrontendDocumentMetadata * FDocumentController : : GetMetadata ( )
{
if ( FMetasoundFrontendDocument * Document = DocumentPtr . Get ( ) )
{
return & Document - > Metadata ;
}
return nullptr ;
}
2021-10-12 21:21:22 -04:00
FConstClassAccessPtr FDocumentController : : FindClass ( const FNodeRegistryKey & InKey ) const
{
return DocumentPtr . GetClassWithRegistryKey ( InKey ) ;
}
2022-01-19 19:32:01 -05:00
FConstClassAccessPtr FDocumentController : : FindOrAddClass ( const FNodeRegistryKey & InKey , bool bInRefreshFromRegistry )
2021-10-12 21:21:22 -04:00
{
if ( FMetasoundFrontendDocument * Document = DocumentPtr . Get ( ) )
{
2022-02-09 13:22:21 -05:00
FClassAccessPtr ClassPtr = DocumentPtr . GetClassWithRegistryKey ( InKey ) ;
2021-10-12 21:21:22 -04:00
2023-03-07 16:49:18 -05:00
auto AddClass = [ this , InKey , Document ] ( FMetasoundFrontendClass & & NewClassDescription , const FGuid & NewClassID )
2021-10-12 21:21:22 -04:00
{
FConstClassAccessPtr NewClassPtr ;
// Cannot add a subgraph using this method because dependencies
// of external graph are not added in this method.
check ( EMetasoundFrontendClassType : : Graph ! = NewClassDescription . Metadata . GetType ( ) ) ;
2022-01-19 19:32:01 -05:00
NewClassDescription . ID = NewClassID ;
2021-10-12 21:21:22 -04:00
Document - > Dependencies . Add ( MoveTemp ( NewClassDescription ) ) ;
NewClassPtr = FindClass ( InKey ) ;
return NewClassPtr ;
} ;
2023-06-20 13:12:39 -04:00
2022-02-09 13:22:21 -05:00
if ( FMetasoundFrontendClass * MetasoundClass = ClassPtr . Get ( ) )
2021-10-12 21:21:22 -04:00
{
// External node classes must match version to return shared definition.
2022-08-10 14:18:10 -04:00
if ( MetasoundClass - > Metadata . GetType ( ) = = EMetasoundFrontendClassType : : Template
| | MetasoundClass - > Metadata . GetType ( ) = = EMetasoundFrontendClassType : : External )
2021-10-12 21:21:22 -04:00
{
// TODO: Assuming we want to recheck classes when they add another
// node, this should be replace with a call to synchronize a
// single class.
2022-01-31 17:23:08 -05:00
FMetasoundFrontendClass NewClass = GenerateClass ( InKey ) ;
2021-10-12 21:21:22 -04:00
if ( NewClass . Metadata . GetVersion ( ) . Major ! = MetasoundClass - > Metadata . GetVersion ( ) . Major )
{
2023-06-20 13:12:39 -04:00
const FGuid ClassId = FDocumentIDGenerator : : Get ( ) . CreateClassID ( * Document ) ;
return AddClass ( MoveTemp ( NewClass ) , ClassId ) ;
2021-10-12 21:21:22 -04:00
}
}
2022-01-19 19:32:01 -05:00
if ( bInRefreshFromRegistry )
{
FGuid ClassID = MetasoundClass - > ID ;
2022-02-09 13:22:21 -05:00
* MetasoundClass = GenerateClass ( InKey ) ;
MetasoundClass - > ID = ClassID ;
return FindClass ( InKey ) ;
2022-01-19 19:32:01 -05:00
}
2021-10-12 21:21:22 -04:00
return ClassPtr ;
}
2022-01-31 17:23:08 -05:00
FMetasoundFrontendClass NewClass = GenerateClass ( InKey ) ;
2023-06-20 13:12:39 -04:00
const FGuid ClassId = FDocumentIDGenerator : : Get ( ) . CreateClassID ( * Document ) ;
return AddClass ( MoveTemp ( NewClass ) , ClassId ) ;
2021-10-12 21:21:22 -04:00
}
return FConstClassAccessPtr ( ) ;
}
FConstClassAccessPtr FDocumentController : : FindClass ( const FMetasoundFrontendClassMetadata & InMetadata ) const
{
return DocumentPtr . GetClassWithMetadata ( InMetadata ) ;
}
FConstClassAccessPtr FDocumentController : : FindOrAddClass ( const FMetasoundFrontendClassMetadata & InMetadata )
{
using FRegistry = FMetasoundFrontendRegistryContainer ;
FConstClassAccessPtr ClassPtr = FindClass ( InMetadata ) ;
if ( const FMetasoundFrontendClass * Class = ClassPtr . Get ( ) )
{
2022-08-10 14:18:10 -04:00
// External & Template node classes must match major version to return shared definition.
if ( EMetasoundFrontendClassType : : External = = InMetadata . GetType ( )
| | EMetasoundFrontendClassType : : Template = = InMetadata . GetType ( ) )
2021-10-12 21:21:22 -04:00
{
if ( InMetadata . GetVersion ( ) . Major ! = Class - > Metadata . GetVersion ( ) . Major )
{
// Mismatched major version. Reset class pointer to null.
ClassPtr = FConstClassAccessPtr ( ) ;
}
}
}
const bool bNoMatchingClassFoundInDocument = ( nullptr = = ClassPtr . Get ( ) ) ;
if ( bNoMatchingClassFoundInDocument )
{
// If no matching class found, attempt to add a class matching the metadata.
if ( FMetasoundFrontendDocument * Document = DocumentPtr . Get ( ) )
{
switch ( InMetadata . GetType ( ) )
{
case EMetasoundFrontendClassType : : External :
2022-08-10 14:18:10 -04:00
case EMetasoundFrontendClassType : : Template :
2021-10-12 21:21:22 -04:00
case EMetasoundFrontendClassType : : Input :
case EMetasoundFrontendClassType : : Output :
{
FMetasoundFrontendClass NewClass ;
2023-10-12 16:37:45 -04:00
FNodeRegistryKey Key = FNodeRegistryKey ( InMetadata ) ;
2021-10-12 21:21:22 -04:00
if ( FRegistry : : GetFrontendClassFromRegistered ( Key , NewClass ) )
{
NewClass . ID = FGuid : : NewGuid ( ) ;
Document - > Dependencies . Add ( NewClass ) ;
}
else
{
2022-02-10 15:07:39 -05:00
# if WITH_EDITOR
2021-10-12 21:21:22 -04:00
UE_LOG ( LogMetaSound , Error ,
TEXT ( " Cannot add external dependency. No Metasound class found with matching registry key [Key:%s, Name:%s, Version:%s]. Suggested solution \" %s \" by %s. " ) ,
2023-10-12 16:37:45 -04:00
* Key . ToString ( ) ,
2021-10-12 21:21:22 -04:00
* InMetadata . GetClassName ( ) . GetFullName ( ) . ToString ( ) ,
* InMetadata . GetVersion ( ) . ToString ( ) ,
* InMetadata . GetPromptIfMissing ( ) . ToString ( ) ,
2022-02-10 15:07:39 -05:00
* InMetadata . GetAuthor ( ) ) ;
# else
UE_LOG ( LogMetaSound , Error ,
TEXT ( " Cannot add external dependency. No Metasound class found with matching registry key [Key:%s, Name:%s, Version:%s]. " ) ,
2023-10-12 16:37:45 -04:00
* Key . ToString ( ) ,
2022-02-10 15:07:39 -05:00
* InMetadata . GetClassName ( ) . GetFullName ( ) . ToString ( ) ,
* InMetadata . GetVersion ( ) . ToString ( ) ) ;
# endif // !WITH_EDITOR
2021-10-12 21:21:22 -04:00
}
}
break ;
case EMetasoundFrontendClassType : : Graph :
{
FMetasoundFrontendGraphClass NewClass ;
NewClass . ID = FGuid : : NewGuid ( ) ;
NewClass . Metadata = InMetadata ;
Document - > Subgraphs . Add ( NewClass ) ;
}
break ;
default :
{
UE_LOG ( LogMetaSound , Error , TEXT (
" Unsupported metasound class type for node: \" %s \" (%s). " ) ,
* InMetadata . GetClassName ( ) . GetFullName ( ) . ToString ( ) ,
* InMetadata . GetVersion ( ) . ToString ( ) ) ;
checkNoEntry ( ) ;
}
}
ClassPtr = FindClass ( InMetadata ) ;
}
}
return ClassPtr ;
}
2022-01-19 19:32:01 -05:00
void FDocumentController : : RemoveUnreferencedDependencies ( )
2021-10-12 21:21:22 -04:00
{
if ( FMetasoundFrontendDocument * Document = DocumentPtr . Get ( ) )
{
int32 NumDependenciesRemovedThisItr = 0 ;
// Repeatedly remove unreferenced dependencies until there are
// no unreferenced dependencies left.
do
{
TSet < FGuid > ReferencedDependencyIDs ;
auto AddNodeClassIDToSet = [ & ] ( const FMetasoundFrontendNode & Node )
{
ReferencedDependencyIDs . Add ( Node . ClassID ) ;
} ;
auto AddGraphNodeClassIDsToSet = [ & ] ( const FMetasoundFrontendGraphClass & GraphClass )
{
Algo : : ForEach ( GraphClass . Graph . Nodes , AddNodeClassIDToSet ) ;
} ;
// Referenced dependencies in root class
Algo : : ForEach ( Document - > RootGraph . Graph . Nodes , AddNodeClassIDToSet ) ;
// Referenced dependencies in subgraphs
Algo : : ForEach ( Document - > Subgraphs , AddGraphNodeClassIDsToSet ) ;
auto IsDependencyUnreferenced = [ & ] ( const FMetasoundFrontendClass & ClassDependency )
{
return ! ReferencedDependencyIDs . Contains ( ClassDependency . ID ) ;
} ;
NumDependenciesRemovedThisItr = Document - > Dependencies . RemoveAllSwap ( IsDependencyUnreferenced ) ;
2022-01-19 19:32:01 -05:00
} while ( NumDependenciesRemovedThisItr > 0 ) ;
2021-10-12 21:21:22 -04:00
}
}
2022-01-19 19:32:01 -05:00
TArray < FConstClassAccessPtr > FDocumentController : : SynchronizeDependencyMetadata ( )
{
TArray < FConstClassAccessPtr > UpdatedClassPtrs ;
if ( FMetasoundFrontendDocument * Document = DocumentPtr . Get ( ) )
{
for ( FMetasoundFrontendClass & Class : Document - > Dependencies )
{
FMetasoundFrontendClass RegistryVersion ;
2023-10-12 16:37:45 -04:00
FNodeRegistryKey RegistryKey ( Class . Metadata ) ;
2022-01-19 19:32:01 -05:00
if ( FMetasoundFrontendRegistryContainer : : Get ( ) - > FindFrontendClassFromRegistered ( RegistryKey , RegistryVersion ) )
{
if ( Class . Metadata . GetChangeID ( ) ! = RegistryVersion . Metadata . GetChangeID ( ) )
{
Class . Metadata = MoveTemp ( RegistryVersion . Metadata ) ;
UpdatedClassPtrs . Add ( FindClass ( RegistryKey ) ) ;
}
}
}
}
return UpdatedClassPtrs ;
}
2021-10-12 21:21:22 -04:00
FGraphHandle FDocumentController : : GetRootGraph ( )
{
if ( IsValid ( ) )
{
FGraphClassAccessPtr GraphClass = DocumentPtr . GetRootGraph ( ) ;
return FGraphController : : CreateGraphHandle ( FGraphController : : FInitParams { GraphClass , this - > AsShared ( ) } ) ;
}
return IGraphController : : GetInvalidHandle ( ) ;
}
FConstGraphHandle FDocumentController : : GetRootGraph ( ) const
{
if ( IsValid ( ) )
{
FConstGraphClassAccessPtr GraphClass = DocumentPtr . GetRootGraph ( ) ;
return FGraphController : : CreateConstGraphHandle ( FGraphController : : FInitParams
{
ConstCastAccessPtr < FGraphClassAccessPtr > ( GraphClass ) ,
ConstCastSharedRef < IDocumentController > ( this - > AsShared ( ) )
} ) ;
}
return IGraphController : : GetInvalidHandle ( ) ;
}
2023-06-20 13:12:39 -04:00
FDocumentAccessPtr FDocumentController : : GetDocumentPtr ( )
{
return DocumentPtr ;
}
const FDocumentAccessPtr FDocumentController : : GetDocumentPtr ( ) const
{
return DocumentPtr ;
}
2021-10-12 21:21:22 -04:00
TArray < FGraphHandle > FDocumentController : : GetSubgraphHandles ( )
{
TArray < FGraphHandle > Subgraphs ;
if ( FMetasoundFrontendDocument * Document = DocumentPtr . Get ( ) )
{
for ( FMetasoundFrontendGraphClass & GraphClass : Document - > Subgraphs )
{
Subgraphs . Add ( GetSubgraphWithClassID ( GraphClass . ID ) ) ;
}
}
return Subgraphs ;
}
TArray < FConstGraphHandle > FDocumentController : : GetSubgraphHandles ( ) const
{
TArray < FConstGraphHandle > Subgraphs ;
if ( const FMetasoundFrontendDocument * Document = DocumentPtr . Get ( ) )
{
for ( const FMetasoundFrontendGraphClass & GraphClass : Document - > Subgraphs )
{
Subgraphs . Add ( GetSubgraphWithClassID ( GraphClass . ID ) ) ;
}
}
return Subgraphs ;
}
FGraphHandle FDocumentController : : GetSubgraphWithClassID ( FGuid InClassID )
{
FGraphClassAccessPtr GraphClassPtr = DocumentPtr . GetSubgraphWithID ( InClassID ) ;
return FGraphController : : CreateGraphHandle ( FGraphController : : FInitParams { GraphClassPtr , this - > AsShared ( ) } ) ;
}
FConstGraphHandle FDocumentController : : GetSubgraphWithClassID ( FGuid InClassID ) const
{
FConstGraphClassAccessPtr GraphClassPtr = DocumentPtr . GetSubgraphWithID ( InClassID ) ;
return FGraphController : : CreateConstGraphHandle ( FGraphController : : FInitParams { ConstCastAccessPtr < FGraphClassAccessPtr > ( GraphClassPtr ) , ConstCastSharedRef < IDocumentController > ( this - > AsShared ( ) ) } ) ;
}
bool FDocumentController : : ExportToJSONAsset ( const FString & InAbsolutePath ) const
{
if ( const FMetasoundFrontendDocument * Document = DocumentPtr . Get ( ) )
{
if ( TUniquePtr < FArchive > FileWriter = TUniquePtr < FArchive > ( IFileManager : : Get ( ) . CreateFileWriter ( * InAbsolutePath ) ) )
{
TJsonStructSerializerBackend < DefaultCharType > Backend ( * FileWriter , EStructSerializerBackendFlags : : Default ) ;
FStructSerializer : : Serialize < FMetasoundFrontendDocument > ( * Document , Backend ) ;
FileWriter - > Close ( ) ;
return true ;
}
else
{
UE_LOG ( LogMetaSound , Error , TEXT ( " Failed to export Metasound json asset. Could not write to path \" %s \" . " ) , * InAbsolutePath ) ;
}
}
return false ;
}
FString FDocumentController : : ExportToJSON ( ) const
{
FString Output ;
if ( const FMetasoundFrontendDocument * Document = DocumentPtr . Get ( ) )
{
TArray < uint8 > WriterBuffer ;
FMemoryWriter MemWriter ( WriterBuffer ) ;
Metasound : : TJsonStructSerializerBackend < Metasound : : DefaultCharType > Backend ( MemWriter , EStructSerializerBackendFlags : : Default ) ;
FStructSerializer : : Serialize < FMetasoundFrontendDocument > ( * Document , Backend ) ;
MemWriter . Close ( ) ;
// null terminator
WriterBuffer . AddZeroed ( sizeof ( ANSICHAR ) ) ;
Output . AppendChars ( reinterpret_cast < ANSICHAR * > ( WriterBuffer . GetData ( ) ) , WriterBuffer . Num ( ) / sizeof ( ANSICHAR ) ) ;
}
return Output ;
}
FDocumentAccess FDocumentController : : ShareAccess ( )
{
FDocumentAccess Access ;
Access . Document = DocumentPtr ;
Access . ConstDocument = DocumentPtr ;
return Access ;
}
FConstDocumentAccess FDocumentController : : ShareAccess ( ) const
{
FConstDocumentAccess Access ;
Access . ConstDocument = DocumentPtr ;
return Access ;
}
}
}
# undef LOCTEXT_NAMESPACE