2021-01-13 10:48:59 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "MetasoundFrontendTransform.h"
2021-06-23 20:08:21 -04:00
# include "Algo/Transform.h"
# include "MetasoundArchetype.h"
2021-07-27 15:36:03 -04:00
# include "MetasoundAssetBase.h"
2021-06-23 20:08:21 -04:00
# include "MetasoundFrontendArchetypeRegistry.h"
2021-08-04 21:02:58 -04:00
# include "MetasoundFrontendDocument.h"
2021-07-27 15:36:03 -04:00
# include "MetasoundFrontendRegistries.h"
2021-06-23 20:08:21 -04:00
# include "MetasoundFrontendSearchEngine.h"
2021-06-08 10:52:31 -04:00
# include "MetasoundLog.h"
2021-06-16 11:21:13 -04:00
# include "Misc/App.h"
2021-01-13 10:48:59 -04:00
namespace Metasound
{
namespace Frontend
{
2021-11-22 15:55:50 -05:00
FModifyRootGraphInterfaces : : FModifyRootGraphInterfaces ( const TArray < FMetasoundFrontendInterface > & InInterfacesToRemove , const TArray < FMetasoundFrontendInterface > & InInterfacesToAdd )
: InterfacesToRemove ( InInterfacesToRemove )
, InterfacesToAdd ( InInterfacesToAdd )
2021-06-23 20:08:21 -04:00
{
2021-11-22 15:55:50 -05:00
Init ( ) ;
}
FModifyRootGraphInterfaces : : FModifyRootGraphInterfaces ( const TArray < FMetasoundFrontendVersion > & InInterfaceVersionsToRemove , const TArray < FMetasoundFrontendVersion > & InInterfaceVersionsToAdd )
{
Algo : : Transform ( InInterfaceVersionsToRemove , InterfacesToRemove , [ ] ( const FMetasoundFrontendVersion & Version )
{
FMetasoundFrontendInterface Interface ;
const bool bFromInterfaceFound = IInterfaceRegistry : : Get ( ) . FindInterface ( GetInterfaceRegistryKey ( Version ) , Interface ) ;
if ( ! ensureAlways ( bFromInterfaceFound ) )
{
UE_LOG ( LogMetaSound , Error , TEXT ( " Failed to find interface '%s' to remove " ) , * Version . ToString ( ) ) ;
}
return Interface ;
} ) ;
Algo : : Transform ( InInterfaceVersionsToAdd , InterfacesToAdd , [ ] ( const FMetasoundFrontendVersion & Version )
{
FMetasoundFrontendInterface Interface ;
const bool bToInterfaceFound = IInterfaceRegistry : : Get ( ) . FindInterface ( GetInterfaceRegistryKey ( Version ) , Interface ) ;
if ( ! ensureAlways ( bToInterfaceFound ) )
{
UE_LOG ( LogMetaSound , Error , TEXT ( " Failed to find interface '%s' to add " ) , * Version . ToString ( ) ) ;
}
return Interface ;
} ) ;
Init ( ) ;
}
void FModifyRootGraphInterfaces : : SetDefaultNodeLocations ( bool bInSetDefaultNodeLocations )
{
bSetDefaultNodeLocations = bInSetDefaultNodeLocations ;
}
2021-12-01 15:59:03 -05:00
void FModifyRootGraphInterfaces : : SetNamePairingFunction ( const TFunction < bool ( FName , FName ) > & InNamePairingFunction )
2021-11-22 15:55:50 -05:00
{
2021-12-01 15:59:03 -05:00
// Reinit required to rebuild list of pairs
Init ( & InNamePairingFunction ) ;
}
void FModifyRootGraphInterfaces : : Init ( const TFunction < bool ( FName , FName ) > * InNamePairingFunction )
{
InputsToRemove . Reset ( ) ;
InputsToAdd . Reset ( ) ;
OutputsToRemove . Reset ( ) ;
OutputsToAdd . Reset ( ) ;
PairedInputs . Reset ( ) ;
PairedOutputs . Reset ( ) ;
2021-11-22 15:55:50 -05:00
for ( const FMetasoundFrontendInterface & FromInterface : InterfacesToRemove )
{
InputsToRemove . Append ( FromInterface . Inputs ) ;
OutputsToRemove . Append ( FromInterface . Outputs ) ;
}
for ( const FMetasoundFrontendInterface & ToInterface : InterfacesToAdd )
{
InputsToAdd . Append ( ToInterface . Inputs ) ;
OutputsToAdd . Append ( ToInterface . Outputs ) ;
}
2021-06-23 20:08:21 -04:00
// Iterate in reverse to allow removal from `InputsToAdd`
for ( int32 AddIndex = InputsToAdd . Num ( ) - 1 ; AddIndex > = 0 ; AddIndex - - )
{
const FMetasoundFrontendClassVertex & VertexToAdd = InputsToAdd [ AddIndex ] ;
2021-12-01 15:59:03 -05:00
const int32 RemoveIndex = InputsToRemove . IndexOfByPredicate ( [ & ] ( const FMetasoundFrontendClassVertex & VertexToRemove )
2021-11-22 15:55:50 -05:00
{
2021-12-01 15:59:03 -05:00
if ( VertexToAdd . TypeName ! = VertexToRemove . TypeName )
{
return false ;
}
if ( InNamePairingFunction & & * InNamePairingFunction )
{
return ( * InNamePairingFunction ) ( VertexToAdd . Name , VertexToRemove . Name ) ;
}
FName ParamA ;
FName ParamB ;
FName Namespace ;
VertexToAdd . SplitName ( Namespace , ParamA ) ;
VertexToRemove . SplitName ( Namespace , ParamB ) ;
return ParamA = = ParamB ;
2021-11-22 15:55:50 -05:00
} ) ;
2021-06-23 20:08:21 -04:00
if ( INDEX_NONE ! = RemoveIndex )
{
PairedInputs . Add ( FVertexPair { InputsToRemove [ RemoveIndex ] , InputsToAdd [ AddIndex ] } ) ;
InputsToRemove . RemoveAtSwap ( RemoveIndex ) ;
InputsToAdd . RemoveAtSwap ( AddIndex ) ;
}
}
// Iterate in reverse to allow removal from `OutputsToAdd`
for ( int32 AddIndex = OutputsToAdd . Num ( ) - 1 ; AddIndex > = 0 ; AddIndex - - )
{
const FMetasoundFrontendClassVertex & VertexToAdd = OutputsToAdd [ AddIndex ] ;
2021-12-01 15:59:03 -05:00
const int32 RemoveIndex = OutputsToRemove . IndexOfByPredicate ( [ & ] ( const FMetasoundFrontendClassVertex & VertexToRemove )
{
if ( VertexToAdd . TypeName ! = VertexToRemove . TypeName )
2021-06-23 20:08:21 -04:00
{
2021-12-01 15:59:03 -05:00
return false ;
}
if ( InNamePairingFunction & & * InNamePairingFunction )
{
return ( * InNamePairingFunction ) ( VertexToAdd . Name , VertexToRemove . Name ) ;
}
FName ParamA ;
FName ParamB ;
FName Namespace ;
VertexToAdd . SplitName ( Namespace , ParamA ) ;
VertexToRemove . SplitName ( Namespace , ParamB ) ;
return ParamA = = ParamB ;
} ) ;
2021-06-23 20:08:21 -04:00
if ( INDEX_NONE ! = RemoveIndex )
{
PairedOutputs . Add ( FVertexPair { OutputsToRemove [ RemoveIndex ] , OutputsToAdd [ AddIndex ] } ) ;
OutputsToRemove . RemoveAtSwap ( RemoveIndex ) ;
OutputsToAdd . RemoveAtSwap ( AddIndex ) ;
}
}
}
2021-11-22 15:55:50 -05:00
bool FModifyRootGraphInterfaces : : Transform ( FDocumentHandle InDocument ) const
2021-06-23 20:08:21 -04:00
{
bool bDidEdit = false ;
2021-11-22 15:55:50 -05:00
FGraphHandle GraphHandle = InDocument - > GetRootGraph ( ) ;
if ( ! ensure ( GraphHandle - > IsValid ( ) ) )
{
return false ;
}
for ( const FMetasoundFrontendInterface & Interface : InterfacesToRemove )
{
InDocument - > RemoveInterfaceVersion ( Interface . Version ) ;
}
for ( const FMetasoundFrontendInterface & Interface : InterfacesToAdd )
{
InDocument - > AddInterfaceVersion ( Interface . Version ) ;
}
2021-06-23 20:08:21 -04:00
// Remove unsupported inputs
for ( const FMetasoundFrontendClassVertex & InputToRemove : InputsToRemove )
{
2021-11-22 15:55:50 -05:00
if ( const FMetasoundFrontendClassInput * ClassInput = GraphHandle - > FindClassInputWithName ( InputToRemove . Name ) . Get ( ) )
2021-06-23 20:08:21 -04:00
{
if ( FMetasoundFrontendClassInput : : IsFunctionalEquivalent ( * ClassInput , InputToRemove ) )
{
bDidEdit = true ;
2021-11-22 15:55:50 -05:00
GraphHandle - > RemoveInputVertex ( InputToRemove . Name ) ;
2021-06-23 20:08:21 -04:00
}
}
}
// Remove unrequired outputs
for ( const FMetasoundFrontendClassVertex & OutputToRemove : OutputsToRemove )
{
2021-11-22 15:55:50 -05:00
if ( const FMetasoundFrontendClassOutput * ClassOutput = GraphHandle - > FindClassOutputWithName ( OutputToRemove . Name ) . Get ( ) )
2021-06-23 20:08:21 -04:00
{
if ( FMetasoundFrontendClassOutput : : IsFunctionalEquivalent ( * ClassOutput , OutputToRemove ) )
{
bDidEdit = true ;
2021-11-22 15:55:50 -05:00
GraphHandle - > RemoveOutputVertex ( OutputToRemove . Name ) ;
2021-06-23 20:08:21 -04:00
}
}
}
2021-08-04 21:02:58 -04:00
auto InputDataTypeCompareFilter = [ ] ( FConstNodeHandle NodeHandle , FName DataType )
{
bool bMatchesDataType = false ;
NodeHandle - > IterateConstOutputs ( [ & ] ( FConstOutputHandle OutputHandle )
{
if ( OutputHandle - > GetDataType ( ) = = DataType )
{
bMatchesDataType = true ;
}
} ) ;
return bMatchesDataType ;
} ;
auto OutputDataTypeCompareFilter = [ ] ( FConstNodeHandle NodeHandle , FName DataType )
{
bool bMatchesDataType = false ;
NodeHandle - > IterateConstInputs ( [ & ] ( FConstInputHandle InputHandle )
{
if ( InputHandle - > GetDataType ( ) = = DataType )
{
bMatchesDataType = true ;
}
} ) ;
return bMatchesDataType ;
} ;
auto FindLowestNodeLocationOfClassType = [ ] ( EMetasoundFrontendClassType ClassType , FGraphHandle Graph , FName DataType , TFunctionRef < bool ( FConstNodeHandle , FName ) > NodeDataTypeFilter )
{
FVector2D LowestLocation ;
Graph - > IterateConstNodes ( [ & ] ( FConstNodeHandle NodeHandle )
{
for ( const TPair < FGuid , FVector2D > & Pair : NodeHandle - > GetNodeStyle ( ) . Display . Locations )
{
if ( Pair . Value . Y > LowestLocation . Y )
{
if ( NodeDataTypeFilter ( NodeHandle , DataType ) )
{
LowestLocation = Pair . Value ;
}
}
}
} , ClassType ) ;
return LowestLocation ;
} ;
2021-06-23 20:08:21 -04:00
// Add missing inputs
2021-11-22 15:55:50 -05:00
for ( const FMetasoundFrontendClassInput & InputToAdd : InputsToAdd )
2021-06-23 20:08:21 -04:00
{
bDidEdit = true ;
2021-11-22 15:55:50 -05:00
FNodeHandle NewInputNode = GraphHandle - > AddInputVertex ( InputToAdd ) ;
2021-08-04 21:02:58 -04:00
2021-11-22 15:55:50 -05:00
if ( bSetDefaultNodeLocations )
{
FMetasoundFrontendNodeStyle Style = NewInputNode - > GetNodeStyle ( ) ;
const FVector2D LastOutputLocation = FindLowestNodeLocationOfClassType ( EMetasoundFrontendClassType : : Input , GraphHandle , InputToAdd . TypeName , InputDataTypeCompareFilter ) ;
Style . Display . Locations . Add ( FGuid ( ) , LastOutputLocation + DisplayStyle : : NodeLayout : : DefaultOffsetY ) ;
NewInputNode - > SetNodeStyle ( Style ) ;
}
2021-06-23 20:08:21 -04:00
}
// Add missing outputs
2021-11-22 15:55:50 -05:00
for ( const FMetasoundFrontendClassOutput & OutputToAdd : OutputsToAdd )
2021-06-23 20:08:21 -04:00
{
bDidEdit = true ;
2021-11-22 15:55:50 -05:00
FNodeHandle NewOutputNode = GraphHandle - > AddOutputVertex ( OutputToAdd ) ;
2021-08-04 21:02:58 -04:00
2021-11-22 15:55:50 -05:00
if ( bSetDefaultNodeLocations )
{
FMetasoundFrontendNodeStyle Style = NewOutputNode - > GetNodeStyle ( ) ;
const FVector2D LastOutputLocation = FindLowestNodeLocationOfClassType ( EMetasoundFrontendClassType : : Output , GraphHandle , OutputToAdd . TypeName , OutputDataTypeCompareFilter ) ;
Style . Display . Locations . Add ( FGuid ( ) , LastOutputLocation + DisplayStyle : : NodeLayout : : DefaultOffsetY ) ;
NewOutputNode - > SetNodeStyle ( Style ) ;
}
2021-06-23 20:08:21 -04:00
}
// Swap paired inputs.
for ( const FVertexPair & InputPair : PairedInputs )
{
bDidEdit = true ;
const FMetasoundFrontendClassVertex & OriginalVertex = InputPair . Get < 0 > ( ) ;
FMetasoundFrontendClassInput NewVertex = InputPair . Get < 1 > ( ) ;
// Cache off node locations and connections to push to new node
TMap < FGuid , FVector2D > Locations ;
TArray < FInputHandle > ConnectedInputs ;
2021-11-22 15:55:50 -05:00
if ( const FMetasoundFrontendClassInput * ClassInput = GraphHandle - > FindClassInputWithName ( OriginalVertex . Name ) . Get ( ) )
2021-06-23 20:08:21 -04:00
{
if ( FMetasoundFrontendVertex : : IsFunctionalEquivalent ( * ClassInput , OriginalVertex ) )
{
NewVertex . DefaultLiteral = ClassInput - > DefaultLiteral ;
2021-11-22 15:55:50 -05:00
NewVertex . NodeID = ClassInput - > NodeID ;
FNodeHandle OriginalInputNode = GraphHandle - > GetInputNodeWithName ( OriginalVertex . Name ) ;
2021-06-23 20:08:21 -04:00
Locations = OriginalInputNode - > GetNodeStyle ( ) . Display . Locations ;
2021-10-12 21:21:22 -04:00
FOutputHandle OriginalInputNodeOutput = OriginalInputNode - > GetOutputWithVertexName ( OriginalVertex . Name ) ;
ConnectedInputs = OriginalInputNodeOutput - > GetConnectedInputs ( ) ;
2021-11-22 15:55:50 -05:00
GraphHandle - > RemoveInputVertex ( OriginalVertex . Name ) ;
2021-06-23 20:08:21 -04:00
}
}
2021-11-22 15:55:50 -05:00
FNodeHandle NewInputNode = GraphHandle - > AddInputVertex ( NewVertex ) ;
2021-06-23 20:08:21 -04:00
// Copy prior node locations
2021-09-13 14:14:37 -04:00
if ( ! Locations . IsEmpty ( ) )
2021-06-23 20:08:21 -04:00
{
// TODO: copy entire style.
FMetasoundFrontendNodeStyle Style = NewInputNode - > GetNodeStyle ( ) ;
Style . Display . Locations = Locations ;
NewInputNode - > SetNodeStyle ( Style ) ;
}
// Copy prior node connections
2021-10-12 21:21:22 -04:00
FOutputHandle OutputHandle = NewInputNode - > GetOutputWithVertexName ( NewVertex . Name ) ;
for ( FInputHandle & ConnectedInput : ConnectedInputs )
2021-06-23 20:08:21 -04:00
{
2021-10-12 21:21:22 -04:00
OutputHandle - > Connect ( * ConnectedInput ) ;
2021-06-23 20:08:21 -04:00
}
}
// Swap paired outputs.
for ( const FVertexPair & OutputPair : PairedOutputs )
{
bDidEdit = true ;
const FMetasoundFrontendClassVertex & OriginalVertex = OutputPair . Get < 0 > ( ) ;
2021-11-22 15:55:50 -05:00
FMetasoundFrontendClassVertex NewVertex = OutputPair . Get < 1 > ( ) ;
2021-06-23 20:08:21 -04:00
// Cache off node locations to push to new node
TMap < FGuid , FVector2D > Locations ;
FOutputHandle ConnectedOutput = IOutputController : : GetInvalidHandle ( ) ;
// Default add output node to origin.
Locations . Add ( FGuid ( ) , FVector2D { 0.f , 0.f } ) ;
2021-11-22 15:55:50 -05:00
if ( const FMetasoundFrontendClassOutput * ClassOutput = GraphHandle - > FindClassOutputWithName ( OriginalVertex . Name ) . Get ( ) )
2021-06-23 20:08:21 -04:00
{
if ( FMetasoundFrontendVertex : : IsFunctionalEquivalent ( * ClassOutput , OriginalVertex ) )
{
2021-11-22 15:55:50 -05:00
NewVertex . NodeID = ClassOutput - > NodeID ;
FNodeHandle OriginalOutputNode = GraphHandle - > GetOutputNodeWithName ( OriginalVertex . Name ) ;
2021-06-23 20:08:21 -04:00
Locations = OriginalOutputNode - > GetNodeStyle ( ) . Display . Locations ;
2021-10-12 21:21:22 -04:00
FInputHandle Input = OriginalOutputNode - > GetInputWithVertexName ( OriginalVertex . Name ) ;
ConnectedOutput = Input - > GetConnectedOutput ( ) ;
2021-11-22 15:55:50 -05:00
GraphHandle - > RemoveOutputVertex ( OriginalVertex . Name ) ;
2021-06-23 20:08:21 -04:00
}
}
2021-11-22 15:55:50 -05:00
FNodeHandle NewOutputNode = GraphHandle - > AddOutputVertex ( NewVertex ) ;
2021-06-23 20:08:21 -04:00
if ( Locations . Num ( ) > 0 )
{
FMetasoundFrontendNodeStyle Style = NewOutputNode - > GetNodeStyle ( ) ;
Style . Display . Locations = Locations ;
NewOutputNode - > SetNodeStyle ( Style ) ;
}
// Copy prior node connections
2021-10-12 21:21:22 -04:00
FInputHandle InputHandle = NewOutputNode - > GetInputWithVertexName ( NewVertex . Name ) ;
ConnectedOutput - > Connect ( * InputHandle ) ;
2021-06-23 20:08:21 -04:00
}
return bDidEdit ;
}
2021-11-22 15:55:50 -05:00
bool FUpdateRootGraphInterface : : Transform ( FDocumentHandle InDocument ) const
2021-01-13 10:48:59 -04:00
{
2021-06-23 20:08:21 -04:00
bool bDidEdit = false ;
2021-11-22 15:55:50 -05:00
if ( ! ensure ( InDocument - > IsValid ( ) ) )
2021-01-13 10:48:59 -04:00
{
2021-06-23 20:08:21 -04:00
return bDidEdit ;
}
2021-11-22 15:55:50 -05:00
// Find registered target interface.
FMetasoundFrontendInterface TargetInterface ;
bool bFoundTargetInterface = ISearchEngine : : Get ( ) . FindInterfaceWithHighestVersion ( InterfaceVersion . Name , TargetInterface ) ;
if ( ! bFoundTargetInterface )
2021-06-23 20:08:21 -04:00
{
2021-11-22 15:55:50 -05:00
UE_LOG ( LogMetaSound , Error , TEXT ( " Target interface is not registered [InterfaceVersion:%s] " ) , * InterfaceVersion . ToString ( ) ) ;
2021-01-13 10:48:59 -04:00
return false ;
}
2021-11-22 15:55:50 -05:00
if ( TargetInterface . Version = = InterfaceVersion )
{
return false ;
}
2021-01-13 10:48:59 -04:00
2021-06-23 20:08:21 -04:00
// Attempt to upgrade
2021-11-22 15:55:50 -05:00
TArray < const IInterfaceRegistryEntry * > UpgradePath ;
GetUpdatePathForDocument ( InterfaceVersion , TargetInterface . Version , UpgradePath ) ;
return UpdateDocumentInterface ( UpgradePath , InDocument ) ;
2021-06-23 20:08:21 -04:00
}
2021-11-22 15:55:50 -05:00
void FUpdateRootGraphInterface : : GetUpdatePathForDocument ( const FMetasoundFrontendVersion & InCurrentVersion , const FMetasoundFrontendVersion & InTargetVersion , TArray < const IInterfaceRegistryEntry * > & OutUpgradePath ) const
2021-06-23 20:08:21 -04:00
{
if ( InCurrentVersion . Name = = InTargetVersion . Name )
{
2021-11-22 15:55:50 -05:00
// Get all associated registered interfaces
TArray < FMetasoundFrontendVersion > RegisteredVersions = ISearchEngine : : Get ( ) . FindAllRegisteredInterfacesWithName ( InTargetVersion . Name ) ;
2021-06-23 20:08:21 -04:00
// Filter registry entries that exist between current version and target version
auto FilterRegistryEntries = [ & InCurrentVersion , & InTargetVersion ] ( const FMetasoundFrontendVersion & InVersion )
2021-01-13 10:48:59 -04:00
{
2021-06-23 20:08:21 -04:00
const bool bIsGreaterThanCurrent = InVersion . Number > InCurrentVersion . Number ;
const bool bIsLessThanOrEqualToTarget = InVersion . Number < = InTargetVersion . Number ;
return bIsGreaterThanCurrent & & bIsLessThanOrEqualToTarget ;
} ;
RegisteredVersions = RegisteredVersions . FilterByPredicate ( FilterRegistryEntries ) ;
// sort registry entries to create an ordered upgrade path.
RegisteredVersions . Sort ( ) ;
// Get registry entries from registry keys.
auto GetRegistryEntry = [ ] ( const FMetasoundFrontendVersion & InVersion )
{
2021-11-22 15:55:50 -05:00
FInterfaceRegistryKey Key = GetInterfaceRegistryKey ( InVersion ) ;
return IInterfaceRegistry : : Get ( ) . FindInterfaceRegistryEntry ( Key ) ;
2021-06-23 20:08:21 -04:00
} ;
Algo : : Transform ( RegisteredVersions , OutUpgradePath , GetRegistryEntry ) ;
}
}
2021-11-22 15:55:50 -05:00
bool FUpdateRootGraphInterface : : UpdateDocumentInterface ( const TArray < const IInterfaceRegistryEntry * > & InUpgradePath , FDocumentHandle InDocument ) const
2021-06-23 20:08:21 -04:00
{
2021-11-22 15:55:50 -05:00
const FMetasoundFrontendVersionNumber * LastVersionUpdated = nullptr ;
for ( const IInterfaceRegistryEntry * Entry : InUpgradePath )
2021-06-23 20:08:21 -04:00
{
if ( ensure ( nullptr ! = Entry ) )
{
2021-11-22 15:55:50 -05:00
if ( Entry - > UpdateRootGraphInterface ( InDocument ) )
2021-03-31 00:23:34 -04:00
{
2021-11-22 15:55:50 -05:00
LastVersionUpdated = & Entry - > GetInterface ( ) . Version . Number ;
2021-03-31 00:23:34 -04:00
}
}
2021-06-23 20:08:21 -04:00
}
2021-11-22 15:55:50 -05:00
if ( LastVersionUpdated )
2021-06-23 20:08:21 -04:00
{
2021-11-22 15:55:50 -05:00
UE_LOG ( LogMetaSound , Display , TEXT ( " Asset '%s' interface '%s' updated: '%s' --> '%s' " ) ,
2021-12-01 15:59:03 -05:00
* InDocument - > GetRootGraphClass ( ) . Metadata . GetDisplayName ( ) . ToString ( ) ,
2021-11-23 19:07:34 -05:00
* InterfaceVersion . Name . ToString ( ) ,
2021-11-22 15:55:50 -05:00
* InterfaceVersion . Number . ToString ( ) ,
* LastVersionUpdated - > ToString ( ) ) ;
return true ;
2021-06-23 20:08:21 -04:00
}
2021-11-22 15:55:50 -05:00
return false ;
2021-01-13 10:48:59 -04:00
}
2021-05-28 14:09:45 -04:00
2021-07-27 15:36:03 -04:00
bool FAutoUpdateRootGraph : : Transform ( FDocumentHandle InDocument ) const
{
bool bDidEdit = false ;
2021-08-18 15:16:57 -04:00
FMetasoundAssetBase * PresetReferencedMetaSoundAsset = nullptr ;
2021-07-27 15:36:03 -04:00
TArray < TPair < FNodeHandle , FMetasoundFrontendVersionNumber > > NodesToUpdate ;
FGraphHandle RootGraph = InDocument - > GetRootGraph ( ) ;
2021-10-12 21:21:22 -04:00
const bool bInterfaceManaged = RootGraph - > GetGraphMetadata ( ) . GetAutoUpdateManagesInterface ( ) ;
2021-07-27 15:36:03 -04:00
RootGraph - > IterateNodes ( [ & ] ( FNodeHandle NodeHandle )
{
using namespace Metasound : : Frontend ;
2021-10-12 21:21:22 -04:00
const FMetasoundFrontendClassMetadata & ClassMetadata = NodeHandle - > GetClassMetadata ( ) ;
if ( bInterfaceManaged )
{
const FNodeRegistryKey RegistryKey = FMetasoundFrontendRegistryContainer : : Get ( ) - > GetRegistryKey ( ClassMetadata ) ;
2021-11-07 23:43:01 -05:00
PresetReferencedMetaSoundAsset = IMetaSoundAssetManager : : GetChecked ( ) . TryLoadAssetFromKey ( RegistryKey ) ;
2021-11-24 15:45:43 -05:00
if ( ! PresetReferencedMetaSoundAsset )
{
UE_LOG ( LogMetaSound , Error , TEXT ( " Failed to update Preset. Referenced asset class '%s' not found. " ) , * ClassMetadata . GetDisplayName ( ) . ToString ( ) ) ;
}
2021-10-12 21:21:22 -04:00
return ;
}
2021-08-09 15:13:40 -04:00
FClassInterfaceUpdates InterfaceUpdates ;
2021-08-18 15:16:57 -04:00
if ( ! NodeHandle - > CanAutoUpdate ( & InterfaceUpdates ) )
2021-07-27 15:36:03 -04:00
{
return ;
}
FMetasoundFrontendVersionNumber UpdateVersion = NodeHandle - > FindHighestMinorVersionInRegistry ( ) ;
if ( UpdateVersion . IsValid ( ) & & UpdateVersion > ClassMetadata . GetVersion ( ) )
{
UE_LOG ( LogMetaSound , Display , TEXT ( " Auto-Updating node class '%s': Newer minor version '%s' found. " ) , * ClassMetadata . GetDisplayName ( ) . ToString ( ) , * UpdateVersion . ToString ( ) ) ;
}
2021-08-09 15:13:40 -04:00
else if ( InterfaceUpdates . ContainsChanges ( ) )
2021-07-27 15:36:03 -04:00
{
UpdateVersion = ClassMetadata . GetVersion ( ) ;
UE_LOG ( LogMetaSound , Display , TEXT ( " Auto-Updating node with class '%s (%s)': Interface change detected. " ) , * ClassMetadata . GetDisplayName ( ) . ToString ( ) , * UpdateVersion . ToString ( ) ) ;
}
NodesToUpdate . Add ( TPair < FNodeHandle , FMetasoundFrontendVersionNumber > ( NodeHandle , UpdateVersion ) ) ;
} , EMetasoundFrontendClassType : : External ) ;
2021-08-18 15:16:57 -04:00
if ( PresetReferencedMetaSoundAsset )
2021-07-27 15:36:03 -04:00
{
2021-11-24 15:45:43 -05:00
if ( bInterfaceManaged )
2021-10-12 21:21:22 -04:00
{
2021-11-24 15:45:43 -05:00
bDidEdit | = FRebuildPresetRootGraph ( PresetReferencedMetaSoundAsset - > GetDocumentHandle ( ) ) . Transform ( InDocument ) ;
if ( bDidEdit )
2021-10-12 21:21:22 -04:00
{
2021-11-24 15:45:43 -05:00
FMetasoundFrontendClassMetadata ParentMetadata = InDocument - > GetRootGraphClass ( ) . Metadata ;
ParentMetadata . SetType ( EMetasoundFrontendClassType : : External ) ;
const FNodeRegistryKey RegistryKey = FMetasoundFrontendRegistryContainer : : Get ( ) - > GetRegistryKey ( ParentMetadata ) ;
FMetasoundAssetBase * ParentMetaSoundAsset = IMetaSoundAssetManager : : GetChecked ( ) . TryLoadAssetFromKey ( RegistryKey ) ;
if ( ensure ( ParentMetaSoundAsset ) )
{
ParentMetaSoundAsset - > ConformObjectDataToInterfaces ( ) ;
}
InDocument - > SynchronizeDependencies ( ) ;
2021-10-12 21:21:22 -04:00
}
}
2021-07-27 15:36:03 -04:00
}
else
{
2021-11-18 14:37:34 -05:00
bDidEdit | = ! NodesToUpdate . IsEmpty ( ) ;
2021-07-27 15:36:03 -04:00
for ( const TPair < FNodeHandle , FMetasoundFrontendVersionNumber > & Pair : NodesToUpdate )
{
FNodeHandle ExistingNode = Pair . Key ;
2021-08-09 15:13:40 -04:00
FMetasoundFrontendVersionNumber InitialVersion = ExistingNode - > GetClassMetadata ( ) . GetVersion ( ) ;
2021-07-27 15:36:03 -04:00
FNodeHandle NewNode = ExistingNode - > ReplaceWithVersion ( Pair . Value ) ;
2021-08-09 15:13:40 -04:00
FMetasoundFrontendNodeStyle Style = NewNode - > GetNodeStyle ( ) ;
Style . bMessageNodeUpdated = NewNode - > GetClassMetadata ( ) . GetVersion ( ) > InitialVersion ;
NewNode - > SetNodeStyle ( Style ) ;
2021-07-27 15:36:03 -04:00
}
2021-11-24 15:45:43 -05:00
InDocument - > SynchronizeDependencies ( ) ;
2021-07-27 15:36:03 -04:00
}
return bDidEdit ;
}
bool FRebuildPresetRootGraph : : Transform ( FDocumentHandle InDocument ) const
{
FGraphHandle RootGraphHandle = InDocument - > GetRootGraph ( ) ;
if ( ! ensure ( RootGraphHandle - > IsValid ( ) ) )
{
return false ;
}
2021-10-12 21:21:22 -04:00
// Callers of this transform should check that the graph is supposed to
// be managed externally before calling this transform. If a scenario
// arises where this transform is used outside of AutoUpdate, then this
// early exist should be removed as it's mostly here to protect against
// accidental manipulation of metasound graphs.
if ( ! ensure ( RootGraphHandle - > GetGraphMetadata ( ) . GetAutoUpdateManagesInterface ( ) ) )
2021-07-27 15:36:03 -04:00
{
return false ;
}
FConstGraphHandle ReferencedGraphHandle = ReferencedDocument - > GetRootGraph ( ) ;
if ( ! ensure ( ReferencedGraphHandle - > IsValid ( ) ) )
{
return false ;
}
2021-10-12 21:21:22 -04:00
// Determine the inputs and outputs needed in the wrapping graph. Also
// cache any exiting literals that have been set on the wrapping graph.
TArray < FMetasoundFrontendClassInput > ClassInputs = GenerateRequiredClassInputs ( RootGraphHandle ) ;
TArray < FMetasoundFrontendClassOutput > ClassOutputs = GenerateRequiredClassOutputs ( RootGraphHandle ) ;
2021-07-27 15:36:03 -04:00
2021-10-12 21:21:22 -04:00
FGuid PresetNodeID ;
RootGraphHandle - > IterateConstNodes ( [ InPresetNodeID = & PresetNodeID ] ( FConstNodeHandle PresetNodeHandle )
2021-07-27 15:36:03 -04:00
{
2021-10-12 21:21:22 -04:00
* InPresetNodeID = PresetNodeHandle - > GetID ( ) ;
} , EMetasoundFrontendClassType : : External ) ;
2021-07-27 15:36:03 -04:00
2021-10-12 21:21:22 -04:00
// Clear the root graph so it can be rebuilt.
2021-07-27 15:36:03 -04:00
RootGraphHandle - > ClearGraph ( ) ;
2021-11-22 15:55:50 -05:00
// Ensure preset interfaces match those found in referenced graph. Referenced graph is assumed to be
// well-formed (i.e. all inputs/outputs/environment variables declared by interfaces are present, and
// of proper name & data type).
2021-12-01 15:59:03 -05:00
const TSet < FMetasoundFrontendVersion > & RefInterfaceVersions = ReferencedDocument - > GetInterfaceVersions ( ) ;
2021-11-22 15:55:50 -05:00
for ( const FMetasoundFrontendVersion & Version : RefInterfaceVersions )
{
InDocument - > AddInterfaceVersion ( Version ) ;
}
2021-10-12 21:21:22 -04:00
// Add referenced node
FMetasoundFrontendClassMetadata ReferencedClassMetadata = ReferencedGraphHandle - > GetGraphMetadata ( ) ;
2021-07-27 15:36:03 -04:00
// Swap type on look-up as it will be referenced as an externally defined class relative to the new Preset asset
ReferencedClassMetadata . SetType ( EMetasoundFrontendClassType : : External ) ;
2021-10-12 21:21:22 -04:00
// Set node location.
FNodeHandle ReferencedNodeHandle = RootGraphHandle - > AddNode ( ReferencedClassMetadata , PresetNodeID ) ;
2021-07-27 15:36:03 -04:00
FMetasoundFrontendNodeStyle RefNodeStyle ;
2021-10-12 21:21:22 -04:00
// Offset to be to the right of input nodes
RefNodeStyle . Display . Locations . Add ( FGuid : : NewGuid ( ) , DisplayStyle : : NodeLayout : : DefaultOffsetX ) ;
2021-07-27 15:36:03 -04:00
ReferencedNodeHandle - > SetNodeStyle ( RefNodeStyle ) ;
2021-10-12 21:21:22 -04:00
// Connect parent graph to referenced graph
AddAndConnectInputs ( ClassInputs , RootGraphHandle , ReferencedNodeHandle ) ;
AddAndConnectOutputs ( ClassOutputs , RootGraphHandle , ReferencedNodeHandle ) ;
2021-07-27 15:36:03 -04:00
return true ;
}
2021-10-12 21:21:22 -04:00
void FRebuildPresetRootGraph : : AddAndConnectInputs ( const TArray < FMetasoundFrontendClassInput > & InClassInputs , FGraphHandle & InParentGraphHandle , FNodeHandle & InReferencedNode ) const
{
// Add inputs and space appropriately
FVector2D InputNodeLocation = FVector2D : : ZeroVector ;
for ( const FMetasoundFrontendClassInput & ClassInput : InClassInputs )
{
FNodeHandle InputNode = InParentGraphHandle - > AddInputVertex ( ClassInput ) ;
if ( ensure ( InputNode - > IsValid ( ) ) )
{
// Set input node location
FMetasoundFrontendNodeStyle NodeStyle ;
NodeStyle . Display . Locations . Add ( FGuid : : NewGuid ( ) , InputNodeLocation ) ;
InputNode - > SetNodeStyle ( NodeStyle ) ;
InputNodeLocation + = DisplayStyle : : NodeLayout : : DefaultOffsetY ;
// Connect input node to corresponding referencing node.
FOutputHandle OutputToConnect = InputNode - > GetOutputWithVertexName ( ClassInput . Name ) ;
FInputHandle InputToConnect = InReferencedNode - > GetInputWithVertexName ( ClassInput . Name ) ;
bool bSuccess = OutputToConnect - > Connect ( * InputToConnect ) ;
check ( bSuccess ) ;
}
}
}
void FRebuildPresetRootGraph : : AddAndConnectOutputs ( const TArray < FMetasoundFrontendClassOutput > & InClassOutputs , FGraphHandle & InParentGraphHandle , FNodeHandle & InReferencedNode ) const
{
// Add outputs and space appropriately
FVector2D OutputNodeLocation = ( 2 * DisplayStyle : : NodeLayout : : DefaultOffsetX ) ;
for ( const FMetasoundFrontendClassOutput & ClassOutput : InClassOutputs )
{
FNodeHandle OutputNode = InParentGraphHandle - > AddOutputVertex ( ClassOutput ) ;
if ( ensure ( OutputNode - > IsValid ( ) ) )
{
// Set input node location
FMetasoundFrontendNodeStyle NodeStyle ;
NodeStyle . Display . Locations . Add ( FGuid : : NewGuid ( ) , OutputNodeLocation ) ;
OutputNode - > SetNodeStyle ( NodeStyle ) ;
OutputNodeLocation + = DisplayStyle : : NodeLayout : : DefaultOffsetY ;
// Connect input node to corresponding referenced node.
FInputHandle InputToConnect = OutputNode - > GetInputWithVertexName ( ClassOutput . Name ) ;
FOutputHandle OutputToConnect = InReferencedNode - > GetOutputWithVertexName ( ClassOutput . Name ) ;
bool bSuccess = InputToConnect - > Connect ( * OutputToConnect ) ;
check ( bSuccess ) ;
}
}
}
TArray < FMetasoundFrontendClassInput > FRebuildPresetRootGraph : : GenerateRequiredClassInputs ( const FConstGraphHandle & InParentGraph ) const
{
TArray < FMetasoundFrontendClassInput > ClassInputs ;
FConstGraphHandle ReferencedGraph = ReferencedDocument - > GetRootGraph ( ) ;
// Iterate through all input nodes of referenced graph
ReferencedGraph - > IterateConstNodes ( [ & ] ( FConstNodeHandle InputNode )
{
const FName NodeName = InputNode - > GetNodeName ( ) ;
FConstInputHandle Input = InputNode - > GetConstInputWithVertexName ( NodeName ) ;
if ( ensure ( Input - > IsValid ( ) ) )
{
FMetasoundFrontendClassInput ClassInput ;
ClassInput . Name = NodeName ;
ClassInput . TypeName = Input - > GetDataType ( ) ;
ClassInput . Metadata . Description = InputNode - > GetDescription ( ) ;
ClassInput . Metadata . DisplayName = Input - > GetMetadata ( ) . DisplayName ;
ClassInput . VertexID = FGuid : : NewGuid ( ) ;
if ( const FMetasoundFrontendClassInput * ExistingClassInput = InParentGraph - > FindClassInputWithName ( NodeName ) . Get ( ) )
{
ClassInput . NodeID = ExistingClassInput - > NodeID ;
}
if ( InParentGraph - > ContainsInputVertex ( NodeName , ClassInput . TypeName ) )
{
// If the input vertex already exists in the parent graph,
// use the default literal value from the parent graph.
FGuid VertexID = InParentGraph - > GetVertexIDForInputVertex ( NodeName ) ;
ClassInput . DefaultLiteral = InParentGraph - > GetDefaultInput ( VertexID ) ;
}
else
{
// If the input vertex does not exist on the parent graph,
// then it is a new vertex and should use the default value
// of the referenced graph.
const FGuid ReferencedVertexID = ReferencedGraph - > GetVertexIDForInputVertex ( NodeName ) ;
ClassInput . DefaultLiteral = ReferencedGraph - > GetDefaultInput ( ReferencedVertexID ) ;
}
ClassInputs . Add ( MoveTemp ( ClassInput ) ) ;
}
} , EMetasoundFrontendClassType : : Input ) ;
return ClassInputs ;
}
TArray < FMetasoundFrontendClassOutput > FRebuildPresetRootGraph : : GenerateRequiredClassOutputs ( const FConstGraphHandle & InParentGraph ) const
{
TArray < FMetasoundFrontendClassOutput > ClassOutputs ;
FConstGraphHandle ReferencedGraph = ReferencedDocument - > GetRootGraph ( ) ;
// Iterate over the referenced graph's output nodes.
ReferencedGraph - > IterateConstNodes ( [ & ] ( FConstNodeHandle OutputNode )
{
const FName NodeName = OutputNode - > GetNodeName ( ) ;
FConstOutputHandle Output = OutputNode - > GetConstOutputWithVertexName ( NodeName ) ;
if ( ensure ( Output - > IsValid ( ) ) )
{
FMetasoundFrontendClassOutput ClassOutput ;
ClassOutput . Name = NodeName ;
ClassOutput . TypeName = Output - > GetDataType ( ) ;
ClassOutput . Metadata . Description = OutputNode - > GetDescription ( ) ;
ClassOutput . Metadata . DisplayName = Output - > GetMetadata ( ) . DisplayName ;
ClassOutput . VertexID = FGuid : : NewGuid ( ) ;
if ( const FMetasoundFrontendClassOutput * ExistingClassOutput = InParentGraph - > FindClassOutputWithName ( NodeName ) . Get ( ) )
{
ClassOutput . NodeID = ExistingClassOutput - > NodeID ;
}
ClassOutputs . Add ( MoveTemp ( ClassOutput ) ) ;
}
} , EMetasoundFrontendClassType : : Output ) ;
return ClassOutputs ;
}
2021-07-27 20:30:14 -04:00
bool FSynchronizeAssetClassDisplayName : : Transform ( FDocumentHandle InDocument ) const
2021-07-27 15:36:03 -04:00
{
const FMetasoundFrontendClassMetadata & Metadata = InDocument - > GetRootGraphClass ( ) . Metadata ;
const FText NewAssetName = FText : : FromString ( AssetName . ToString ( ) ) ;
if ( Metadata . GetDisplayName ( ) . CompareTo ( NewAssetName ) ! = 0 )
{
FMetasoundFrontendClassMetadata NewMetadata = Metadata ;
NewMetadata . SetDisplayName ( NewAssetName ) ;
InDocument - > GetRootGraph ( ) - > SetGraphMetadata ( NewMetadata ) ;
2021-07-27 20:30:14 -04:00
return true ;
2021-07-27 15:36:03 -04:00
}
2021-07-27 20:30:14 -04:00
return false ;
}
bool FRegenerateAssetClassName : : Transform ( FDocumentHandle InDocument ) const
{
FMetasoundFrontendClassMetadata Metadata = InDocument - > GetRootGraph ( ) - > GetGraphMetadata ( ) ;
FMetasoundFrontendClassName NewName = Metadata . GetClassName ( ) ;
NewName . Name = * FGuid : : NewGuid ( ) . ToString ( ) ;
Metadata . SetClassName ( NewName ) ;
InDocument - > GetRootGraph ( ) - > SetGraphMetadata ( Metadata ) ;
2021-07-27 15:36:03 -04:00
return true ;
}
2021-05-28 14:09:45 -04:00
// Versioning Transforms
class FVersionDocumentTransform : public IDocumentTransform
{
protected :
virtual FMetasoundFrontendVersionNumber GetTargetVersion ( ) const = 0 ;
virtual void TransformInternal ( FDocumentHandle InDocument ) const = 0 ;
public :
bool Transform ( FDocumentHandle InDocument ) const override
{
const FMetasoundFrontendDocumentMetadata & Metadata = InDocument - > GetMetadata ( ) ;
if ( Metadata . Version . Number > = GetTargetVersion ( ) )
{
return false ;
}
TransformInternal ( InDocument ) ;
FMetasoundFrontendDocumentMetadata NewMetadata = Metadata ;
NewMetadata . Version . Number = GetTargetVersion ( ) ;
InDocument - > SetMetadata ( NewMetadata ) ;
return true ;
}
} ;
/** Versions document from 1.0 to 1.1. */
class FVersionDocument_1_1 : public FVersionDocumentTransform
{
public :
FMetasoundFrontendVersionNumber GetTargetVersion ( ) const override
{
2021-06-08 10:52:31 -04:00
return { 1 , 1 } ;
2021-05-28 14:09:45 -04:00
}
void TransformInternal ( FDocumentHandle InDocument ) const override
{
FGraphHandle GraphHandle = InDocument - > GetRootGraph ( ) ;
TArray < FNodeHandle > FrontendNodes = GraphHandle - > GetNodes ( ) ;
2021-06-14 16:46:19 -04:00
// Before literals could be stored on node inputs directly, they were stored
// by creating hidden input nodes. Update the doc by finding all hidden input
// nodes, placing the literal value of the input node directly on the
// downstream node's input. Then delete the hidden input node.
2021-05-28 14:09:45 -04:00
for ( FNodeHandle & NodeHandle : FrontendNodes )
{
2021-06-14 16:46:19 -04:00
const bool bIsHiddenNode = NodeHandle - > GetNodeStyle ( ) . Display . Visibility = = EMetasoundFrontendNodeStyleDisplayVisibility : : Hidden ;
2021-07-27 15:36:03 -04:00
const bool bIsInputNode = EMetasoundFrontendClassType : : Input = = NodeHandle - > GetClassMetadata ( ) . GetType ( ) ;
2021-06-14 16:46:19 -04:00
const bool bIsHiddenInputNode = bIsHiddenNode & & bIsInputNode ;
if ( bIsHiddenInputNode )
2021-05-28 14:09:45 -04:00
{
2021-06-14 16:46:19 -04:00
// Get literal value from input node.
2021-05-28 14:09:45 -04:00
const FGuid VertexID = GraphHandle - > GetVertexIDForInputVertex ( NodeHandle - > GetNodeName ( ) ) ;
const FMetasoundFrontendLiteral DefaultLiteral = GraphHandle - > GetDefaultInput ( VertexID ) ;
2021-06-14 16:46:19 -04:00
// Apply literal value to downstream node's inputs.
2021-05-28 14:09:45 -04:00
TArray < FOutputHandle > OutputHandles = NodeHandle - > GetOutputs ( ) ;
if ( ensure ( OutputHandles . Num ( ) = = 1 ) )
{
FOutputHandle OutputHandle = OutputHandles [ 0 ] ;
TArray < FInputHandle > Inputs = OutputHandle - > GetConnectedInputs ( ) ;
OutputHandle - > Disconnect ( ) ;
for ( FInputHandle & Input : Inputs )
{
if ( const FMetasoundFrontendLiteral * Literal = Input - > GetClassDefaultLiteral ( ) )
{
if ( ! Literal - > IsEquivalent ( DefaultLiteral ) )
{
Input - > SetLiteral ( DefaultLiteral ) ;
}
}
else
{
Input - > SetLiteral ( DefaultLiteral ) ;
}
}
}
2021-06-14 16:46:19 -04:00
GraphHandle - > RemoveNode ( * NodeHandle ) ;
2021-05-28 14:09:45 -04:00
}
}
}
} ;
2021-06-08 10:52:31 -04:00
/** Versions document from 1.1 to 1.2. */
class FVersionDocument_1_2 : public FVersionDocumentTransform
{
private :
const FName Name ;
const FString & Path ;
public :
FVersionDocument_1_2 ( const FName InName , const FString & InPath )
: Name ( InName )
, Path ( InPath )
{
}
FMetasoundFrontendVersionNumber GetTargetVersion ( ) const override
{
2021-06-16 11:21:13 -04:00
return { 1 , 2 } ;
2021-06-08 10:52:31 -04:00
}
void TransformInternal ( FDocumentHandle InDocument ) const override
{
2021-07-27 15:36:03 -04:00
const FMetasoundFrontendGraphClass & GraphClass = InDocument - > GetRootGraphClass ( ) ;
FMetasoundFrontendClassMetadata Metadata = GraphClass . Metadata ;
2021-06-08 10:52:31 -04:00
2021-07-27 15:36:03 -04:00
Metadata . SetClassName ( { " GraphAsset " , Name , * Path } ) ;
Metadata . SetDisplayName ( FText : : FromString ( Name . ToString ( ) ) ) ;
InDocument - > GetRootGraph ( ) - > SetGraphMetadata ( Metadata ) ;
2021-06-16 11:21:13 -04:00
}
} ;
2021-06-08 10:52:31 -04:00
2021-06-23 20:08:21 -04:00
/** Versions document from 1.2 to 1.3. */
2021-06-16 11:21:13 -04:00
class FVersionDocument_1_3 : public FVersionDocumentTransform
{
public :
FVersionDocument_1_3 ( )
{
}
FMetasoundFrontendVersionNumber GetTargetVersion ( ) const override
{
2021-06-23 20:08:21 -04:00
return { 1 , 3 } ;
2021-06-16 11:21:13 -04:00
}
void TransformInternal ( FDocumentHandle InDocument ) const override
{
2021-07-27 15:36:03 -04:00
const FMetasoundFrontendGraphClass & GraphClass = InDocument - > GetRootGraphClass ( ) ;
FMetasoundFrontendClassMetadata Metadata = GraphClass . Metadata ;
2021-06-16 11:21:13 -04:00
2021-07-27 15:36:03 -04:00
Metadata . SetClassName ( FMetasoundFrontendClassName { FName ( ) , * FGuid : : NewGuid ( ) . ToString ( ) , FName ( ) } ) ;
InDocument - > GetRootGraph ( ) - > SetGraphMetadata ( Metadata ) ;
2021-06-08 10:52:31 -04:00
}
} ;
2021-06-23 20:08:21 -04:00
/** Versions document from 1.3 to 1.4. */
class FVersionDocument_1_4 : public FVersionDocumentTransform
{
public :
FVersionDocument_1_4 ( )
{
}
FMetasoundFrontendVersionNumber GetTargetVersion ( ) const override
{
return { 1 , 4 } ;
}
void TransformInternal ( FDocumentHandle InDocument ) const override
{
check ( InDocument - > GetMetadata ( ) . Version . Number . Major = = 1 ) ;
check ( InDocument - > GetMetadata ( ) . Version . Number . Minor = = 3 ) ;
2021-12-01 15:59:03 -05:00
const TSet < FMetasoundFrontendVersion > & Interfaces = InDocument - > GetInterfaceVersions ( ) ;
2021-06-23 20:08:21 -04:00
2021-12-01 15:59:03 -05:00
// Version 1.3 did not have an "InterfaceVersion" property on the
2021-06-23 20:08:21 -04:00
// document, so any document that is being updated should start off
2021-11-22 15:55:50 -05:00
// with an "Invalid" interface version.
2021-12-01 15:59:03 -05:00
if ( ensure ( Interfaces . IsEmpty ( ) ) )
2021-06-23 20:08:21 -04:00
{
2021-11-22 15:55:50 -05:00
constexpr bool bIncludeDeprecatedInterfaces = true ;
TArray < FMetasoundFrontendInterface > AllInterfaces = ISearchEngine : : Get ( ) . FindAllInterfaces ( bIncludeDeprecatedInterfaces ) ;
2021-06-23 20:08:21 -04:00
const FMetasoundFrontendGraphClass & RootGraph = InDocument - > GetRootGraphClass ( ) ;
const TArray < FMetasoundFrontendClass > & Dependencies = InDocument - > GetDependencies ( ) ;
const TArray < FMetasoundFrontendGraphClass > & Subgraphs = InDocument - > GetSubgraphs ( ) ;
2021-11-22 15:55:50 -05:00
if ( const FMetasoundFrontendInterface * Interface = FindMostSimilarInterfaceSupportingEnvironment ( RootGraph , Dependencies , Subgraphs , AllInterfaces ) )
2021-06-23 20:08:21 -04:00
{
2021-11-22 15:55:50 -05:00
UE_LOG ( LogMetaSound , Display , TEXT ( " Assigned interface [InterfaceVersion:%s] to document [RootGraphClassName:%s] " ) ,
* Interface - > Version . ToString ( ) , * RootGraph . Metadata . GetClassName ( ) . ToString ( ) ) ;
2021-06-23 20:08:21 -04:00
2021-11-22 15:55:50 -05:00
InDocument - > AddInterfaceVersion ( Interface - > Version ) ;
2021-06-23 20:08:21 -04:00
}
else
{
2021-11-22 15:55:50 -05:00
UE_LOG ( LogMetaSound , Warning , TEXT ( " Failed to find interface for document [RootGraphClassName:%s] " ) ,
2021-07-27 15:36:03 -04:00
* RootGraph . Metadata . GetClassName ( ) . ToString ( ) ) ;
2021-06-23 20:08:21 -04:00
}
}
}
} ;
2021-07-27 15:36:03 -04:00
/** Versions document from 1.4 to 1.5. */
class FVersionDocument_1_5 : public FVersionDocumentTransform
{
public :
FVersionDocument_1_5 ( FName InAssetName )
: AssetName ( InAssetName )
{
}
FMetasoundFrontendVersionNumber GetTargetVersion ( ) const override
{
return { 1 , 5 } ;
}
void TransformInternal ( FDocumentHandle InDocument ) const override
{
2021-07-27 20:30:14 -04:00
FSynchronizeAssetClassDisplayName ( AssetName ) . Transform ( InDocument ) ;
2021-07-27 15:36:03 -04:00
}
private :
FName AssetName ;
} ;
2021-07-27 20:30:14 -04:00
/** Versions document from 1.5 to 1.6. */
class FVersionDocument_1_6 : public FVersionDocumentTransform
{
public :
FVersionDocument_1_6 ( )
{
}
FMetasoundFrontendVersionNumber GetTargetVersion ( ) const override
{
return { 1 , 6 } ;
}
void TransformInternal ( FDocumentHandle InDocument ) const override
{
FRegenerateAssetClassName ( ) . Transform ( InDocument ) ;
}
} ;
2021-09-13 14:14:37 -04:00
/** Versions document from 1.6 to 1.7. */
class FVersionDocument_1_7 : public FVersionDocumentTransform
{
public :
FVersionDocument_1_7 ( ) = default ;
FMetasoundFrontendVersionNumber GetTargetVersion ( ) const override
{
return { 1 , 7 } ;
}
void TransformInternal ( FDocumentHandle InDocument ) const override
{
auto RenameTransform = [ ] ( FNodeHandle NodeHandle )
{
// Required nodes are all (at the point of this transform) providing
// unique names and customized display names (ex. 'Audio' for both mono &
// L/R output, On Play, & 'On Finished'), so do not replace them by nulling
// out the guid as a name and using the converted FName of the FText DisplayName.
2021-11-22 15:55:50 -05:00
if ( ! NodeHandle - > IsInterfaceMember ( ) )
2021-09-13 14:14:37 -04:00
{
const FName NewNodeName = * NodeHandle - > GetDisplayName ( ) . ToString ( ) ;
NodeHandle - > IterateInputs ( [ & ] ( FInputHandle InputHandle )
{
InputHandle - > SetName ( NewNodeName ) ;
} ) ;
NodeHandle - > IterateOutputs ( [ & ] ( FOutputHandle OutputHandle )
{
OutputHandle - > SetName ( NewNodeName ) ;
} ) ;
NodeHandle - > SetDisplayName ( FText ( ) ) ;
NodeHandle - > SetNodeName ( NewNodeName ) ;
}
} ;
InDocument - > GetRootGraph ( ) - > IterateNodes ( RenameTransform , EMetasoundFrontendClassType : : Input ) ;
InDocument - > GetRootGraph ( ) - > IterateNodes ( RenameTransform , EMetasoundFrontendClassType : : Output ) ;
}
} ;
2021-06-08 10:52:31 -04:00
FVersionDocument : : FVersionDocument ( FName InName , const FString & InPath )
: Name ( InName )
, Path ( InPath )
{
}
2021-05-28 14:09:45 -04:00
bool FVersionDocument : : Transform ( FDocumentHandle InDocument ) const
{
if ( ! ensure ( InDocument - > IsValid ( ) ) )
{
return false ;
}
bool bWasUpdated = false ;
2021-07-27 20:30:14 -04:00
const FMetasoundFrontendVersionNumber InitVersionNumber = InDocument - > GetMetadata ( ) . Version . Number ;
2021-05-28 14:09:45 -04:00
// Add additional transforms here after defining them above, example below.
bWasUpdated | = FVersionDocument_1_1 ( ) . Transform ( InDocument ) ;
2021-06-08 10:52:31 -04:00
bWasUpdated | = FVersionDocument_1_2 ( Name , Path ) . Transform ( InDocument ) ;
2021-06-16 11:21:13 -04:00
bWasUpdated | = FVersionDocument_1_3 ( ) . Transform ( InDocument ) ;
2021-06-23 20:08:21 -04:00
bWasUpdated | = FVersionDocument_1_4 ( ) . Transform ( InDocument ) ;
2021-07-27 15:36:03 -04:00
bWasUpdated | = FVersionDocument_1_5 ( Name ) . Transform ( InDocument ) ;
2021-07-27 20:30:14 -04:00
bWasUpdated | = FVersionDocument_1_6 ( ) . Transform ( InDocument ) ;
2021-09-13 14:14:37 -04:00
bWasUpdated | = FVersionDocument_1_7 ( ) . Transform ( InDocument ) ;
2021-07-27 20:30:14 -04:00
if ( bWasUpdated )
{
const FText & DisplayName = InDocument - > GetRootGraph ( ) - > GetGraphMetadata ( ) . GetDisplayName ( ) ;
const FMetasoundFrontendVersionNumber NewVersionNumber = InDocument - > GetMetadata ( ) . Version . Number ;
UE_LOG ( LogMetaSound , Display , TEXT ( " MetaSound Graph '%s' Parent Document Versioned: '%s' --> '%s' " ) , * DisplayName . ToString ( ) , * InitVersionNumber . ToString ( ) , * NewVersionNumber . ToString ( ) ) ;
}
2021-06-16 11:21:13 -04:00
2021-05-28 14:09:45 -04:00
return bWasUpdated ;
}
2021-03-31 00:23:34 -04:00
} // namespace Frontend
} // namespace Metasound