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"
2022-01-18 18:06:06 -05:00
# include "MetasoundTrace.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
{
2022-03-16 19:27:27 -04:00
namespace DocumentTransform
{
# if WITH_EDITOR
2022-03-17 16:56:13 -04:00
FGetNodeDisplayNameProjection NodeDisplayNameProjection ;
2022-03-16 19:27:27 -04:00
2022-03-17 16:56:13 -04:00
void RegisterNodeDisplayNameProjection ( FGetNodeDisplayNameProjection & & InNameProjection )
2022-03-16 19:27:27 -04:00
{
2022-03-17 16:56:13 -04:00
NodeDisplayNameProjection = MoveTemp ( InNameProjection ) ;
2022-03-16 19:27:27 -04:00
}
2022-03-17 16:56:13 -04:00
FGetNodeDisplayNameProjectionRef GetNodeDisplayNameProjection ( )
2022-03-16 19:27:27 -04:00
{
2022-03-17 16:56:13 -04:00
return NodeDisplayNameProjection ;
2022-03-16 19:27:27 -04:00
}
# endif // WITH_EDITOR
} // namespace DocumentTransform
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 ( ) ;
}
2022-02-10 15:07:39 -05:00
# if WITH_EDITOR
2021-11-22 15:55:50 -05:00
void FModifyRootGraphInterfaces : : SetDefaultNodeLocations ( bool bInSetDefaultNodeLocations )
{
bSetDefaultNodeLocations = bInSetDefaultNodeLocations ;
}
2022-02-10 15:07:39 -05:00
# endif // WITH_EDITOR
2021-11-22 15:55:50 -05:00
2021-12-10 20:37:31 -05:00
void FModifyRootGraphInterfaces : : SetNamePairingFunction ( const TFunction < bool ( FName , FName ) > & InNamePairingFunction )
2021-11-22 15:55:50 -05:00
{
2021-12-10 20:37:31 -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 ) ;
}
2022-02-25 09:45:49 -05:00
// This function combines all the inputs of all interfaces into one input list and ptrs to their originating interfaces.
// The interface ptr will be used to query the interface for required validations on inputs. Interfaces define required inputs (and possibly other validation requirements).
2021-11-22 15:55:50 -05:00
for ( const FMetasoundFrontendInterface & ToInterface : InterfacesToAdd )
{
2022-02-25 09:45:49 -05:00
TArray < FInputData > NewInputDataArray ;
for ( const FMetasoundFrontendClassInput & Input : ToInterface . Inputs )
{
FInputData NewData ;
NewData . Input = Input ;
NewData . InputInterface = & ToInterface ;
NewInputDataArray . Add ( NewData ) ;
}
InputsToAdd . Append ( NewInputDataArray ) ;
TArray < FOutputData > NewOutputDataArray ;
for ( const FMetasoundFrontendClassOutput & Output : ToInterface . Outputs )
{
FOutputData NewData ;
NewData . Output = Output ;
NewData . OutputInterface = & ToInterface ;
NewOutputDataArray . Add ( NewData ) ;
}
OutputsToAdd . Append ( NewOutputDataArray ) ;
2021-11-22 15:55:50 -05:00
}
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 - - )
{
2022-02-25 09:45:49 -05:00
const FMetasoundFrontendClassVertex & VertexToAdd = InputsToAdd [ AddIndex ] . Input ;
2021-06-23 20:08:21 -04:00
2021-12-10 20:37:31 -05:00
const int32 RemoveIndex = InputsToRemove . IndexOfByPredicate ( [ & ] ( const FMetasoundFrontendClassVertex & VertexToRemove )
2021-11-22 15:55:50 -05:00
{
2021-12-10 20:37:31 -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 )
{
2022-02-25 09:45:49 -05:00
PairedInputs . Add ( FVertexPair { InputsToRemove [ RemoveIndex ] , InputsToAdd [ AddIndex ] . Input } ) ;
2021-06-23 20:08:21 -04:00
InputsToRemove . RemoveAtSwap ( RemoveIndex ) ;
InputsToAdd . RemoveAtSwap ( AddIndex ) ;
}
}
// Iterate in reverse to allow removal from `OutputsToAdd`
for ( int32 AddIndex = OutputsToAdd . Num ( ) - 1 ; AddIndex > = 0 ; AddIndex - - )
{
2022-02-25 09:45:49 -05:00
const FMetasoundFrontendClassVertex & VertexToAdd = OutputsToAdd [ AddIndex ] . Output ;
2021-06-23 20:08:21 -04:00
2021-12-10 20:37:31 -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-10 20:37:31 -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 )
{
2022-02-25 09:45:49 -05:00
PairedOutputs . Add ( FVertexPair { OutputsToRemove [ RemoveIndex ] , OutputsToAdd [ AddIndex ] . Output } ) ;
2021-06-23 20:08:21 -04:00
OutputsToRemove . RemoveAtSwap ( RemoveIndex ) ;
OutputsToAdd . RemoveAtSwap ( AddIndex ) ;
}
2022-02-25 09:45:49 -05:00
}
2021-06-23 20:08:21 -04:00
}
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 ;
} ;
2022-02-10 15:07:39 -05:00
# if WITH_EDITOR
2021-08-04 21:02:58 -04:00
auto FindLowestNodeLocationOfClassType = [ ] ( EMetasoundFrontendClassType ClassType , FGraphHandle Graph , FName DataType , TFunctionRef < bool ( FConstNodeHandle , FName ) > NodeDataTypeFilter )
{
2022-02-25 09:45:49 -05:00
FVector2D LowestLocation = { TNumericLimits < float > : : Min ( ) , TNumericLimits < float > : : Min ( ) } ;
bool bFoundLocation = false ;
2021-08-04 21:02:58 -04:00
Graph - > IterateConstNodes ( [ & ] ( FConstNodeHandle NodeHandle )
{
2022-02-25 09:45:49 -05:00
const TMap < FGuid , FVector2D > & Locations = NodeHandle - > GetNodeStyle ( ) . Display . Locations ;
for ( const TPair < FGuid , FVector2D > & Pair : Locations )
2021-08-04 21:02:58 -04:00
{
if ( Pair . Value . Y > LowestLocation . Y )
{
2022-02-25 09:45:49 -05:00
LowestLocation = Pair . Value ;
bFoundLocation = true ;
2021-08-04 21:02:58 -04:00
}
}
} , ClassType ) ;
2022-02-25 09:45:49 -05:00
if ( ! bFoundLocation )
{
LowestLocation = { DisplayStyle : : NodeLayout : : DefaultOffsetX . X * 2.0f , 0.0f } ;
}
2021-08-04 21:02:58 -04:00
return LowestLocation ;
} ;
2022-02-10 15:07:39 -05:00
# endif // WITH_EDITOR
2021-08-04 21:02:58 -04:00
2021-06-23 20:08:21 -04:00
// Add missing inputs
2022-02-25 09:45:49 -05:00
for ( const FInputData & InputData : InputsToAdd )
2021-06-23 20:08:21 -04:00
{
bDidEdit = true ;
2022-02-25 09:45:49 -05:00
const FMetasoundFrontendClassInput & InputToAdd = InputData . Input ;
2021-11-22 15:55:50 -05:00
FNodeHandle NewInputNode = GraphHandle - > AddInputVertex ( InputToAdd ) ;
2021-08-04 21:02:58 -04:00
2022-02-10 15:07:39 -05:00
# if WITH_EDITOR
2022-02-25 09:45:49 -05:00
FName InputName = InputToAdd . Name ;
bool bRequiredInput = InputData . InputInterface - > GetInputStyle ( ) . RequiredMembers . Contains ( InputName ) ;
if ( bSetDefaultNodeLocations | | bRequiredInput )
2021-11-22 15:55:50 -05:00
{
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 ) ;
}
2022-02-10 15:07:39 -05:00
# endif // WITH_EDITOR
2021-06-23 20:08:21 -04:00
}
// Add missing outputs
2022-02-25 09:45:49 -05:00
for ( const FOutputData & OutputData : OutputsToAdd )
2021-06-23 20:08:21 -04:00
{
bDidEdit = true ;
2022-02-25 09:45:49 -05:00
const FMetasoundFrontendClassOutput & OutputToAdd = OutputData . Output ;
2021-11-22 15:55:50 -05:00
FNodeHandle NewOutputNode = GraphHandle - > AddOutputVertex ( OutputToAdd ) ;
2021-08-04 21:02:58 -04:00
2022-02-10 15:07:39 -05:00
# if WITH_EDITOR
2022-02-25 09:45:49 -05:00
FName OutputName = OutputToAdd . Name ;
bool bRequiredOutput = OutputData . OutputInterface - > GetOutputStyle ( ) . RequiredMembers . Contains ( OutputName ) ;
if ( bSetDefaultNodeLocations | | bRequiredOutput )
2021-11-22 15:55:50 -05:00
{
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 ) ;
}
2022-02-10 15:07:39 -05:00
# endif // WITH_EDITOR
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 ) ;
2022-02-10 15:07:39 -05:00
# if WITH_EDITOR
2021-06-23 20:08:21 -04:00
Locations = OriginalInputNode - > GetNodeStyle ( ) . Display . Locations ;
2022-02-10 15:07:39 -05:00
# endif // WITH_EDITOR
2021-06-23 20:08:21 -04:00
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 ) ;
2022-02-10 15:07:39 -05:00
# if WITH_EDITOR
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 ) ;
}
2022-02-10 15:07:39 -05:00
# endif // WITH_EDITOR
2021-06-23 20:08:21 -04:00
// 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
2022-02-10 15:07:39 -05:00
# if WITH_EDITOR
2021-06-23 20:08:21 -04:00
// Cache off node locations to push to new node
// Default add output node to origin.
2022-02-10 15:07:39 -05:00
TMap < FGuid , FVector2D > Locations ;
2021-06-23 20:08:21 -04:00
Locations . Add ( FGuid ( ) , FVector2D { 0.f , 0.f } ) ;
2022-02-10 15:07:39 -05:00
# endif // WITH_EDITOR
FOutputHandle ConnectedOutput = IOutputController : : GetInvalidHandle ( ) ;
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 ;
2022-01-26 18:11:52 -05:00
2022-02-10 15:07:39 -05:00
# if WITH_EDITOR
2022-01-26 18:11:52 -05:00
// Interface members do not serialize text to avoid localization
// mismatches between assets and interfaces defined in code.
NewVertex . Metadata . SetSerializeText ( false ) ;
2022-02-10 15:07:39 -05:00
# endif // WITH_EDITOR
2022-01-26 18:11:52 -05:00
2021-11-22 15:55:50 -05:00
FNodeHandle OriginalOutputNode = GraphHandle - > GetOutputNodeWithName ( OriginalVertex . Name ) ;
2022-02-10 15:07:39 -05:00
# if WITH_EDITOR
2021-06-23 20:08:21 -04:00
Locations = OriginalOutputNode - > GetNodeStyle ( ) . Display . Locations ;
2022-02-10 15:07:39 -05:00
# endif // WITH_EDITOR
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
2022-02-10 15:07:39 -05:00
# if WITH_EDITOR
2021-06-23 20:08:21 -04:00
if ( Locations . Num ( ) > 0 )
{
FMetasoundFrontendNodeStyle Style = NewOutputNode - > GetNodeStyle ( ) ;
Style . Display . Locations = Locations ;
NewOutputNode - > SetNodeStyle ( Style ) ;
}
2022-02-10 15:07:39 -05:00
# endif // WITH_EDITOR
2021-06-23 20:08:21 -04:00
// 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
{
2022-02-10 15:07:39 -05:00
# if WITH_EDITOR
const FString AssetName = * InDocument - > GetRootGraphClass ( ) . Metadata . GetDisplayName ( ) . ToString ( ) ;
# else
const FString AssetName = * InDocument - > GetRootGraphClass ( ) . Metadata . GetClassName ( ) . ToString ( ) ;
# endif // !WITH_EDITOR
2021-11-22 15:55:50 -05:00
UE_LOG ( LogMetaSound , Display , TEXT ( " Asset '%s' interface '%s' updated: '%s' --> '%s' " ) ,
2022-02-10 15:07:39 -05:00
* AssetName ,
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
{
2022-01-18 18:06:06 -05:00
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( FAutoUpdateRootGraph : : Transform ) ;
2021-07-27 15:36:03 -04:00
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 ( ) ;
2022-02-09 12:52:07 -05:00
const bool bIsPreset = RootGraph - > GetGraphPresetOptions ( ) . bIsPreset ;
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 ( ) ;
2022-02-09 12:52:07 -05:00
if ( bIsPreset )
2021-10-12 21:21:22 -04:00
{
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 )
{
2022-01-27 00:45:28 -05:00
UE_LOG ( LogMetaSound , Error , TEXT ( " Auto-Updating preset '%s' failed: Referenced class '%s' missing. " ) , * DebugAssetPath , * ClassMetadata . GetClassName ( ) . ToString ( ) ) ;
2021-11-24 15:45:43 -05:00
}
2021-10-12 21:21:22 -04:00
return ;
}
2021-08-09 15:13:40 -04:00
FClassInterfaceUpdates InterfaceUpdates ;
2022-01-31 15:53:54 -05:00
if ( ! NodeHandle - > CanAutoUpdate ( InterfaceUpdates ) )
2021-07-27 15:36:03 -04:00
{
return ;
}
2022-04-25 16:59:41 -04:00
// Check if a updated minor version exists.
FMetasoundFrontendClass ClassWithHighestMinorVersion ;
bool bFoundClassInSearchEngine = Frontend : : ISearchEngine : : Get ( ) . FindClassWithHighestMinorVersion ( ClassMetadata . GetClassName ( ) , ClassMetadata . GetVersion ( ) . Major , ClassWithHighestMinorVersion ) ;
if ( bFoundClassInSearchEngine & & ( ClassWithHighestMinorVersion . Metadata . GetVersion ( ) > ClassMetadata . GetVersion ( ) ) )
2021-07-27 15:36:03 -04:00
{
2022-04-25 16:59:41 -04:00
const FMetasoundFrontendVersionNumber UpdateVersion = ClassWithHighestMinorVersion . Metadata . GetVersion ( ) ;
2022-01-27 00:45:28 -05:00
UE_LOG ( LogMetaSound , Display , TEXT ( " Auto-Updating '%s' node class '%s': Newer version '%s' found. " ) , * DebugAssetPath , * ClassMetadata . GetClassName ( ) . ToString ( ) , * UpdateVersion . ToString ( ) ) ;
2022-01-31 15:53:54 -05:00
NodesToUpdate . Add ( TPair < FNodeHandle , FMetasoundFrontendVersionNumber > ( NodeHandle , UpdateVersion ) ) ;
2021-07-27 15:36:03 -04:00
}
2021-08-09 15:13:40 -04:00
else if ( InterfaceUpdates . ContainsChanges ( ) )
2021-07-27 15:36:03 -04:00
{
2022-04-25 16:59:41 -04:00
const FMetasoundFrontendVersionNumber UpdateVersion = ClassMetadata . GetVersion ( ) ;
2022-01-27 00:45:28 -05:00
UE_LOG ( LogMetaSound , Display , TEXT ( " Auto-Updating '%s' node class '%s (%s)': Interface change detected. " ) , * DebugAssetPath , * ClassMetadata . GetClassName ( ) . ToString ( ) , * UpdateVersion . ToString ( ) ) ;
2022-01-31 15:53:54 -05:00
NodesToUpdate . Add ( TPair < FNodeHandle , FMetasoundFrontendVersionNumber > ( NodeHandle , UpdateVersion ) ) ;
2021-07-27 15:36:03 -04:00
}
2022-01-31 15:53:54 -05:00
// Only update the node at this point if editor data is loaded. If it isn't and their are no interface
// changes but auto-update returned it was eligible, then the auto-update only contains cosmetic changes.
# if WITH_EDITORONLY_DATA
else
{
2022-04-25 16:59:41 -04:00
NodesToUpdate . Add ( TPair < FNodeHandle , FMetasoundFrontendVersionNumber > ( NodeHandle , ClassMetadata . GetVersion ( ) ) ) ;
2022-01-31 15:53:54 -05:00
}
# endif // WITH_EDITORONLY_DATA
2021-07-27 15:36:03 -04:00
} , EMetasoundFrontendClassType : : External ) ;
2021-08-18 15:16:57 -04:00
if ( PresetReferencedMetaSoundAsset )
2021-07-27 15:36:03 -04:00
{
2022-02-09 12:52:07 -05:00
if ( bIsPreset )
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
{
2022-02-09 12:52:07 -05:00
FMetasoundFrontendClassMetadata PresetMetadata = InDocument - > GetRootGraphClass ( ) . Metadata ;
PresetMetadata . SetType ( EMetasoundFrontendClassType : : External ) ;
const FNodeRegistryKey RegistryKey = FMetasoundFrontendRegistryContainer : : Get ( ) - > GetRegistryKey ( PresetMetadata ) ;
FMetasoundAssetBase * PresetMetaSoundAsset = IMetaSoundAssetManager : : GetChecked ( ) . TryLoadAssetFromKey ( RegistryKey ) ;
if ( ensure ( PresetMetaSoundAsset ) )
2021-11-24 15:45:43 -05:00
{
2022-02-09 12:52:07 -05:00
PresetMetaSoundAsset - > ConformObjectDataToInterfaces ( ) ;
2021-11-24 15:45:43 -05:00
}
2022-01-19 19:32:01 -05:00
InDocument - > RemoveUnreferencedDependencies ( ) ;
InDocument - > SynchronizeDependencyMetadata ( ) ;
2021-10-12 21:21:22 -04:00
}
}
2021-07-27 15:36:03 -04:00
}
else
{
2022-03-01 21:25:04 -05:00
using FVertexNameAndType = INodeController : : FVertexNameAndType ;
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 ( ) ;
2022-03-01 21:25:04 -05:00
TArray < FVertexNameAndType > DisconnectedInputs ;
TArray < FVertexNameAndType > DisconnectedOutputs ;
FNodeHandle NewNode = ExistingNode - > ReplaceWithVersion ( Pair . Value , & DisconnectedInputs , & DisconnectedOutputs ) ;
// Log warnings for any disconnections
if ( bLogWarningOnDroppedConnection )
{
if ( ( DisconnectedInputs . Num ( ) > 0 ) | | ( DisconnectedOutputs . Num ( ) > 0 ) )
{
const FString NodeClassName = NewNode - > GetClassMetadata ( ) . GetClassName ( ) . ToString ( ) ;
const FString NewClassVersion = Pair . Value . ToString ( ) ;
for ( const FVertexNameAndType & InputPin : DisconnectedInputs )
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Auto-Updating '%s' node class '%s (%s)': Previously connected input '%s' with data type '%s' no longer exists. " ) , * DebugAssetPath , * NodeClassName , * NewClassVersion , * InputPin . Get < 0 > ( ) . ToString ( ) , * InputPin . Get < 1 > ( ) . ToString ( ) ) ;
}
for ( const FVertexNameAndType & OutputPin : DisconnectedOutputs )
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Auto-Updating '%s' node class '%s (%s)': Previously connected output '%s' with data type '%s' no longer exists. " ) , * DebugAssetPath , * NodeClassName , * NewClassVersion , * OutputPin . Get < 0 > ( ) . ToString ( ) , * OutputPin . Get < 1 > ( ) . ToString ( ) ) ;
}
}
}
2021-07-27 15:36:03 -04:00
}
2021-11-24 15:45:43 -05:00
2022-01-19 19:32:01 -05:00
InDocument - > RemoveUnreferencedDependencies ( ) ;
InDocument - > SynchronizeDependencyMetadata ( ) ;
2021-07-27 15:36:03 -04:00
}
return bDidEdit ;
}
bool FRebuildPresetRootGraph : : Transform ( FDocumentHandle InDocument ) const
{
2022-02-09 12:52:07 -05:00
FGraphHandle PresetGraphHandle = InDocument - > GetRootGraph ( ) ;
if ( ! ensure ( PresetGraphHandle - > IsValid ( ) ) )
2021-07-27 15:36:03 -04:00
{
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.
2022-02-09 12:52:07 -05:00
if ( ! ensure ( PresetGraphHandle - > GetGraphPresetOptions ( ) . bIsPreset ) )
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.
2022-02-09 12:52:07 -05:00
TSet < FName > InputsInheritingDefault ;
TArray < FMetasoundFrontendClassInput > ClassInputs = GenerateRequiredClassInputs ( PresetGraphHandle , InputsInheritingDefault ) ;
TArray < FMetasoundFrontendClassOutput > ClassOutputs = GenerateRequiredClassOutputs ( PresetGraphHandle ) ;
2021-07-27 15:36:03 -04:00
2021-10-12 21:21:22 -04:00
FGuid PresetNodeID ;
2022-02-09 12:52:07 -05:00
PresetGraphHandle - > 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.
2022-02-09 12:52:07 -05:00
PresetGraphHandle - > ClearGraph ( ) ;
2021-07-27 15:36:03 -04:00
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-10 20:37:31 -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 ) ;
2022-02-09 12:52:07 -05:00
FNodeHandle ReferencedNodeHandle = PresetGraphHandle - > AddNode ( ReferencedClassMetadata , PresetNodeID ) ;
2022-02-10 15:07:39 -05:00
2022-03-16 19:27:27 -04:00
# if WITH_EDITOR
2022-02-10 15:07:39 -05:00
// Set node location.
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
2022-03-02 22:11:18 -05:00
RefNodeStyle . Display . Locations . Add ( FGuid ( ) , DisplayStyle : : NodeLayout : : DefaultOffsetX ) ;
2021-07-27 15:36:03 -04:00
ReferencedNodeHandle - > SetNodeStyle ( RefNodeStyle ) ;
2022-02-10 15:07:39 -05:00
# endif // WITH_EDITOR
2021-07-27 15:36:03 -04:00
2021-10-12 21:21:22 -04:00
// Connect parent graph to referenced graph
2022-02-09 12:52:07 -05:00
PresetGraphHandle - > SetInputsInheritingDefault ( MoveTemp ( InputsInheritingDefault ) ) ;
AddAndConnectInputs ( ClassInputs , PresetGraphHandle , ReferencedNodeHandle ) ;
AddAndConnectOutputs ( ClassOutputs , PresetGraphHandle , ReferencedNodeHandle ) ;
2021-07-27 15:36:03 -04:00
return true ;
}
2022-02-09 12:52:07 -05:00
void FRebuildPresetRootGraph : : AddAndConnectInputs ( const TArray < FMetasoundFrontendClassInput > & InClassInputs , FGraphHandle & InPresetGraphHandle , FNodeHandle & InReferencedNode ) const
2021-10-12 21:21:22 -04:00
{
// Add inputs and space appropriately
FVector2D InputNodeLocation = FVector2D : : ZeroVector ;
2022-03-02 22:11:18 -05:00
FConstGraphHandle ReferencedGraphHandle = ReferencedDocument - > GetRootGraph ( ) ;
TArray < FNodeHandle > NodeHandles ;
2021-10-12 21:21:22 -04:00
for ( const FMetasoundFrontendClassInput & ClassInput : InClassInputs )
{
2022-02-09 12:52:07 -05:00
FNodeHandle InputNode = InPresetGraphHandle - > AddInputVertex ( ClassInput ) ;
2021-10-12 21:21:22 -04:00
if ( ensure ( InputNode - > IsValid ( ) ) )
{
// Connect input node to corresponding referencing node.
FOutputHandle OutputToConnect = InputNode - > GetOutputWithVertexName ( ClassInput . Name ) ;
FInputHandle InputToConnect = InReferencedNode - > GetInputWithVertexName ( ClassInput . Name ) ;
2022-03-02 22:11:18 -05:00
ensure ( OutputToConnect - > Connect ( * InputToConnect ) ) ;
NodeHandles . Add ( MoveTemp ( InputNode ) ) ;
2021-10-12 21:21:22 -04:00
}
}
2022-03-02 22:11:18 -05:00
# if WITH_EDITOR
// Sort before adding nodes to graph layout & copy to preset (must be done after all
// inputs/outputs are added but before setting locations to propagate effectively)
FMetasoundFrontendInterfaceStyle Style = ReferencedGraphHandle - > GetInputStyle ( ) ;
InPresetGraphHandle - > SetInputStyle ( Style ) ;
2022-03-16 19:27:27 -04:00
2022-03-17 16:56:13 -04:00
Style . SortDefaults ( NodeHandles , DocumentTransform : : GetNodeDisplayNameProjection ( ) ) ;
2022-03-02 22:11:18 -05:00
for ( const FNodeHandle & InputNode : NodeHandles )
{
// Set input node location
FMetasoundFrontendNodeStyle NodeStyle ;
NodeStyle . Display . Locations . Add ( FGuid ( ) , InputNodeLocation ) ;
InputNode - > SetNodeStyle ( NodeStyle ) ;
InputNodeLocation + = DisplayStyle : : NodeLayout : : DefaultOffsetY ;
}
# endif // WITH_EDITOR
2021-10-12 21:21:22 -04:00
}
2022-02-09 12:52:07 -05:00
void FRebuildPresetRootGraph : : AddAndConnectOutputs ( const TArray < FMetasoundFrontendClassOutput > & InClassOutputs , FGraphHandle & InPresetGraphHandle , FNodeHandle & InReferencedNode ) const
2021-10-12 21:21:22 -04:00
{
// Add outputs and space appropriately
FVector2D OutputNodeLocation = ( 2 * DisplayStyle : : NodeLayout : : DefaultOffsetX ) ;
2022-03-02 22:11:18 -05:00
FConstGraphHandle ReferencedGraphHandle = ReferencedDocument - > GetRootGraph ( ) ;
TArray < FNodeHandle > NodeHandles ;
2021-10-12 21:21:22 -04:00
for ( const FMetasoundFrontendClassOutput & ClassOutput : InClassOutputs )
{
2022-02-09 12:52:07 -05:00
FNodeHandle OutputNode = InPresetGraphHandle - > AddOutputVertex ( ClassOutput ) ;
2021-10-12 21:21:22 -04:00
if ( ensure ( OutputNode - > IsValid ( ) ) )
{
// Connect input node to corresponding referenced node.
FInputHandle InputToConnect = OutputNode - > GetInputWithVertexName ( ClassOutput . Name ) ;
FOutputHandle OutputToConnect = InReferencedNode - > GetOutputWithVertexName ( ClassOutput . Name ) ;
2022-03-02 22:11:18 -05:00
ensure ( InputToConnect - > Connect ( * OutputToConnect ) ) ;
NodeHandles . Add ( MoveTemp ( OutputNode ) ) ;
2021-10-12 21:21:22 -04:00
}
}
2022-03-02 22:11:18 -05:00
# if WITH_EDITOR
// Sort before adding nodes to graph layout & copy to preset (must be done after all
// inputs/outputs are added but before setting locations to propagate effectively)
FMetasoundFrontendInterfaceStyle Style = ReferencedGraphHandle - > GetOutputStyle ( ) ;
InPresetGraphHandle - > SetOutputStyle ( Style ) ;
2022-03-17 16:56:13 -04:00
Style . SortDefaults ( NodeHandles , DocumentTransform : : GetNodeDisplayNameProjection ( ) ) ;
2022-03-16 19:27:27 -04:00
// Set input node location
2022-03-02 22:11:18 -05:00
for ( const FNodeHandle & OutputNode : NodeHandles )
{
FMetasoundFrontendNodeStyle NodeStyle ;
NodeStyle . Display . Locations . Add ( FGuid ( ) , OutputNodeLocation ) ;
OutputNode - > SetNodeStyle ( NodeStyle ) ;
OutputNodeLocation + = DisplayStyle : : NodeLayout : : DefaultOffsetY ;
}
# endif // WITH_EDITOR
2021-10-12 21:21:22 -04:00
}
2022-02-09 12:52:07 -05:00
TArray < FMetasoundFrontendClassInput > FRebuildPresetRootGraph : : GenerateRequiredClassInputs ( const FConstGraphHandle & InPresetGraph , TSet < FName > & OutInputsInheritingDefault ) const
2021-10-12 21:21:22 -04:00
{
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 ( ) ;
2022-01-26 18:11:52 -05:00
2022-02-10 15:07:39 -05:00
# if WITH_EDITOR
2022-01-26 18:11:52 -05:00
ClassInput . Metadata . SetDescription ( InputNode - > GetDescription ( ) ) ;
ClassInput . Metadata . SetDisplayName ( Input - > GetMetadata ( ) . GetDisplayName ( ) ) ;
2022-02-10 15:07:39 -05:00
# endif // WITH_EDITOR
2022-01-26 18:11:52 -05:00
2021-10-12 21:21:22 -04:00
ClassInput . VertexID = FGuid : : NewGuid ( ) ;
2022-02-09 12:52:07 -05:00
if ( const FMetasoundFrontendClassInput * ExistingClassInput = InPresetGraph - > FindClassInputWithName ( NodeName ) . Get ( ) )
2021-10-12 21:21:22 -04:00
{
ClassInput . NodeID = ExistingClassInput - > NodeID ;
}
2022-02-09 12:52:07 -05:00
if ( InPresetGraph - > ContainsInputVertex ( NodeName , ClassInput . TypeName ) )
2021-10-12 21:21:22 -04:00
{
// If the input vertex already exists in the parent graph,
2022-02-09 12:52:07 -05:00
// check if parent should be used or not from set of managed
// input names.
if ( InPresetGraph - > GetInputsInheritingDefault ( ) . Contains ( NodeName ) )
{
const FGuid ReferencedVertexID = ReferencedGraph - > GetVertexIDForInputVertex ( NodeName ) ;
ClassInput . DefaultLiteral = ReferencedGraph - > GetDefaultInput ( ReferencedVertexID ) ;
}
else
{
FGuid VertexID = InPresetGraph - > GetVertexIDForInputVertex ( NodeName ) ;
ClassInput . DefaultLiteral = InPresetGraph - > GetDefaultInput ( VertexID ) ;
}
2021-10-12 21:21:22 -04:00
}
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 ) ;
2022-02-09 12:52:07 -05:00
// Fill new managed inputs set with names of all class inputs & if the old input was explicitly not
// marked as a managed input, then remove it from the new managed inputs if found.
OutInputsInheritingDefault . Reset ( ) ;
Algo : : Transform ( ClassInputs , OutInputsInheritingDefault , [ ] ( const FMetasoundFrontendClassInput & Input ) { return Input . Name ; } ) ;
const TSet < FName > & InputsInheritingDefault = InPresetGraph - > GetInputsInheritingDefault ( ) ;
InPresetGraph - > IterateConstNodes ( [ & InputsInheritingDefault , & OutInputsInheritingDefault ] ( FConstNodeHandle Input )
{
if ( ! InputsInheritingDefault . Contains ( Input - > GetNodeName ( ) ) )
{
OutInputsInheritingDefault . Remove ( Input - > GetNodeName ( ) ) ;
}
} , EMetasoundFrontendClassType : : Input ) ;
2021-10-12 21:21:22 -04:00
return ClassInputs ;
}
2022-02-09 12:52:07 -05:00
TArray < FMetasoundFrontendClassOutput > FRebuildPresetRootGraph : : GenerateRequiredClassOutputs ( const FConstGraphHandle & InPresetGraph ) const
2021-10-12 21:21:22 -04:00
{
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 ( ) ;
2022-01-26 18:11:52 -05:00
2022-02-10 15:07:39 -05:00
# if WITH_EDITOR
2022-01-26 18:11:52 -05:00
ClassOutput . Metadata . SetDescription ( OutputNode - > GetDescription ( ) ) ;
ClassOutput . Metadata . SetDisplayName ( Output - > GetMetadata ( ) . GetDisplayName ( ) ) ;
2022-02-10 15:07:39 -05:00
# endif // WITH_EDITOR
2022-01-26 18:11:52 -05:00
2021-10-12 21:21:22 -04:00
ClassOutput . VertexID = FGuid : : NewGuid ( ) ;
2022-02-09 12:52:07 -05:00
if ( const FMetasoundFrontendClassOutput * ExistingClassOutput = InPresetGraph - > FindClassOutputWithName ( NodeName ) . Get ( ) )
2021-10-12 21:21:22 -04:00
{
ClassOutput . NodeID = ExistingClassOutput - > NodeID ;
}
ClassOutputs . Add ( MoveTemp ( ClassOutput ) ) ;
}
} , EMetasoundFrontendClassType : : Output ) ;
return ClassOutputs ;
}
2022-03-10 21:19:13 -05:00
bool FRenameRootGraphClass : : Transform ( FDocumentHandle InDocument ) const
2021-07-27 20:30:14 -04:00
{
2022-03-10 21:19:13 -05:00
FGraphHandle RootGraph = InDocument - > GetRootGraph ( ) ;
FMetasoundFrontendClassMetadata Metadata = RootGraph - > GetGraphMetadata ( ) ;
Metadata . SetClassName ( NewClassName ) ;
RootGraph - > 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
{
2022-02-10 15:07:39 -05:00
FName Name ;
const FString & Path ;
2021-05-28 14:09:45 -04:00
public :
2022-02-10 15:07:39 -05:00
FVersionDocument_1_1 ( FName InName , const FString & InPath )
: Name ( InName )
, Path ( InPath )
{
}
2021-05-28 14:09:45 -04:00
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
{
2022-02-10 15:07:39 -05:00
# if WITH_EDITOR
2021-05-28 14:09:45 -04:00
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 ( ) )
{
2022-02-09 19:27:40 -05:00
if ( ! Literal - > IsEqual ( DefaultLiteral ) )
2021-05-28 14:09:45 -04:00
{
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
}
}
2022-02-10 15:07:39 -05:00
# else
UE_LOG ( LogMetaSound , Error , TEXT ( " Asset '%s' at '%s' must be saved with editor enabled in order to version document to target version '%s'. " ) , * Name . ToString ( ) , * Path , * GetTargetVersion ( ) . ToString ( ) ) ;
# endif // !WITH_EDITOR
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
{
2022-02-10 15:07:39 -05:00
# if WITH_EDITOR
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 ) ;
2022-02-10 15:07:39 -05:00
# else
UE_LOG ( LogMetaSound , Error , TEXT ( " Asset '%s' at '%s' must be saved with editor enabled in order to version document to target version '%s'. " ) , * Name . ToString ( ) , * Path , * GetTargetVersion ( ) . ToString ( ) ) ;
# endif // !WITH_EDITOR
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-10 20:37:31 -05:00
const TSet < FMetasoundFrontendVersion > & Interfaces = InDocument - > GetInterfaceVersions ( ) ;
2021-06-23 20:08:21 -04:00
2021-12-10 20:37:31 -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-10 20:37:31 -05:00
if ( ensure ( Interfaces . IsEmpty ( ) ) )
2021-06-23 20:08:21 -04:00
{
2022-04-25 16:59:41 -04:00
// At the time when version 1.4 of the document was introduced,
// these were the only available interfaces.
static const FMetasoundFrontendVersion PreexistingInterfaceVersions [ ] = {
FMetasoundFrontendVersion { " MetaSound " , { 1 , 0 } } ,
FMetasoundFrontendVersion { " MonoSource " , { 1 , 0 } } ,
FMetasoundFrontendVersion { " StereoSource " , { 1 , 0 } } ,
FMetasoundFrontendVersion { " MonoSource " , { 1 , 1 } } ,
FMetasoundFrontendVersion { " StereoSource " , { 1 , 1 } }
} ;
static const int32 NumPreexistingInterfaceVersions = sizeof ( PreexistingInterfaceVersions ) / sizeof ( PreexistingInterfaceVersions [ 0 ] ) ;
TArray < FMetasoundFrontendInterface > CandidateInterfaces ;
IInterfaceRegistry & InterfaceRegistry = IInterfaceRegistry : : Get ( ) ;
for ( int32 i = 0 ; i < NumPreexistingInterfaceVersions ; i + + )
{
FMetasoundFrontendInterface Interface ;
if ( InterfaceRegistry . FindInterface ( GetInterfaceRegistryKey ( PreexistingInterfaceVersions [ i ] ) , Interface ) )
{
CandidateInterfaces . Add ( Interface ) ;
}
}
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 ( ) ;
2022-04-25 16:59:41 -04:00
if ( const FMetasoundFrontendInterface * Interface = FindMostSimilarInterfaceSupportingEnvironment ( RootGraph , Dependencies , Subgraphs , CandidateInterfaces ) )
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
{
2022-02-10 15:07:39 -05:00
FName Name ;
const FString & Path ;
2021-07-27 15:36:03 -04:00
public :
2022-02-10 15:07:39 -05:00
FVersionDocument_1_5 ( FName InName , const FString & InPath )
: Name ( InName )
, Path ( InPath )
2021-07-27 15:36:03 -04:00
{
}
FMetasoundFrontendVersionNumber GetTargetVersion ( ) const override
{
return { 1 , 5 } ;
}
void TransformInternal ( FDocumentHandle InDocument ) const override
{
2022-02-10 15:07:39 -05:00
# if WITH_EDITOR
2022-02-02 02:19:16 -05:00
const FMetasoundFrontendClassMetadata & Metadata = InDocument - > GetRootGraphClass ( ) . Metadata ;
2022-02-10 15:07:39 -05:00
const FText NewAssetName = FText : : FromString ( Name . ToString ( ) ) ;
2022-02-02 02:19:16 -05:00
if ( Metadata . GetDisplayName ( ) . CompareTo ( NewAssetName ) ! = 0 )
{
FMetasoundFrontendClassMetadata NewMetadata = Metadata ;
NewMetadata . SetDisplayName ( NewAssetName ) ;
InDocument - > GetRootGraph ( ) - > SetGraphMetadata ( NewMetadata ) ;
}
2022-02-10 15:07:39 -05:00
# else
UE_LOG ( LogMetaSound , Error , TEXT ( " Asset '%s' at '%s' must be saved with editor enabled in order to version document to target version '%s'. " ) , * Name . ToString ( ) , * Path , * GetTargetVersion ( ) . ToString ( ) ) ;
# endif // !WITH_EDITOR
2021-07-27 15:36:03 -04:00
}
} ;
2021-07-27 20:30:14 -04:00
/** Versions document from 1.5 to 1.6. */
class FVersionDocument_1_6 : public FVersionDocumentTransform
{
public :
2022-03-10 21:19:13 -05:00
FVersionDocument_1_6 ( ) = default ;
2021-07-27 20:30:14 -04:00
FMetasoundFrontendVersionNumber GetTargetVersion ( ) const override
{
return { 1 , 6 } ;
}
void TransformInternal ( FDocumentHandle InDocument ) const override
{
2022-03-10 21:19:13 -05:00
const FGuid NewAssetClassID = FGuid : : NewGuid ( ) ;
FRenameRootGraphClass : : Generate ( InDocument , NewAssetClassID ) ;
2021-07-27 20:30:14 -04:00
}
} ;
2021-09-13 14:14:37 -04:00
/** Versions document from 1.6 to 1.7. */
class FVersionDocument_1_7 : public FVersionDocumentTransform
{
2022-02-10 15:07:39 -05:00
FName Name ;
const FString & Path ;
2021-09-13 14:14:37 -04:00
public :
2022-02-10 15:07:39 -05:00
FVersionDocument_1_7 ( FName InName , const FString & InPath )
: Name ( InName )
, Path ( InPath )
{
}
2021-09-13 14:14:37 -04:00
FMetasoundFrontendVersionNumber GetTargetVersion ( ) const override
{
return { 1 , 7 } ;
}
void TransformInternal ( FDocumentHandle InDocument ) const override
{
2022-02-10 15:07:39 -05:00
# if WITH_EDITOR
2021-09-13 14:14:37 -04:00
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 ) ;
2022-02-10 15:07:39 -05:00
# else
UE_LOG ( LogMetaSound , Error , TEXT ( " Asset '%s' at '%s' must be saved with editor enabled in order to version document to target version '%s'. " ) , * Name . ToString ( ) , * Path , * GetTargetVersion ( ) . ToString ( ) ) ;
# endif // !WITH_EDITOR
2021-09-13 14:14:37 -04:00
}
} ;
2022-01-26 18:11:52 -05:00
/** Versions document from 1.7 to 1.8. */
class FVersionDocument_1_8 : public FVersionDocumentTransform
{
2022-02-10 15:07:39 -05:00
FName Name ;
const FString & Path ;
2022-01-26 18:11:52 -05:00
public :
2022-02-10 15:07:39 -05:00
FVersionDocument_1_8 ( FName InName , const FString & InPath )
: Name ( InName )
, Path ( InPath )
{
}
2022-01-26 18:11:52 -05:00
FMetasoundFrontendVersionNumber GetTargetVersion ( ) const override
{
return { 1 , 8 } ;
}
void TransformInternal ( FDocumentHandle InDocument ) const override
{
2022-02-10 15:07:39 -05:00
# if WITH_EDITOR
2022-01-26 18:11:52 -05:00
// Do not serialize MetaData text for dependencies as
// CacheRegistryData dynamically provides this.
InDocument - > IterateDependencies ( [ ] ( FMetasoundFrontendClass & Dependency )
{
constexpr bool bSerializeText = false ;
Dependency . Metadata . SetSerializeText ( bSerializeText ) ;
for ( FMetasoundFrontendClassInput & Input : Dependency . Interface . Inputs )
{
Input . Metadata . SetSerializeText ( false ) ;
}
for ( FMetasoundFrontendClassOutput & Output : Dependency . Interface . Outputs )
{
Output . Metadata . SetSerializeText ( false ) ;
}
} ) ;
const TSet < FMetasoundFrontendVersion > & InterfaceVersions = InDocument - > GetInterfaceVersions ( ) ;
using FNameDataTypePair = TPair < FName , FName > ;
TSet < FNameDataTypePair > InterfaceInputs ;
TSet < FNameDataTypePair > InterfaceOutputs ;
for ( const FMetasoundFrontendVersion & Version : InterfaceVersions )
{
FInterfaceRegistryKey RegistryKey = GetInterfaceRegistryKey ( Version ) ;
const IInterfaceRegistryEntry * Entry = IInterfaceRegistry : : Get ( ) . FindInterfaceRegistryEntry ( RegistryKey ) ;
if ( ensure ( Entry ) )
{
const FMetasoundFrontendInterface & Interface = Entry - > GetInterface ( ) ;
Algo : : Transform ( Interface . Inputs , InterfaceInputs , [ ] ( const FMetasoundFrontendClassInput & Input )
{
return FNameDataTypePair ( Input . Name , Input . TypeName ) ;
} ) ;
Algo : : Transform ( Interface . Outputs , InterfaceOutputs , [ ] ( const FMetasoundFrontendClassOutput & Output )
{
return FNameDataTypePair ( Output . Name , Output . TypeName ) ;
} ) ;
}
}
// Only serialize MetaData text for inputs owned by the graph (not by interfaces)
FMetasoundFrontendGraphClass RootGraphClass = InDocument - > GetRootGraphClass ( ) ;
for ( FMetasoundFrontendClassInput & Input : RootGraphClass . Interface . Inputs )
{
const bool bSerializeText = ! InterfaceInputs . Contains ( FNameDataTypePair ( Input . Name , Input . TypeName ) ) ;
Input . Metadata . SetSerializeText ( bSerializeText ) ;
}
// Only serialize MetaData text for outputs owned by the graph (not by interfaces)
for ( FMetasoundFrontendClassOutput & Output : RootGraphClass . Interface . Outputs )
{
const bool bSerializeText = ! InterfaceOutputs . Contains ( FNameDataTypePair ( Output . Name , Output . TypeName ) ) ;
Output . Metadata . SetSerializeText ( bSerializeText ) ;
}
InDocument - > SetRootGraphClass ( MoveTemp ( RootGraphClass ) ) ;
2022-02-10 15:07:39 -05:00
# else
UE_LOG ( LogMetaSound , Error , TEXT ( " Asset '%s' at '%s' must be saved with editor enabled in order to version document to target version '%s'. " ) , * Name . ToString ( ) , * Path , * GetTargetVersion ( ) . ToString ( ) ) ;
# endif // !WITH_EDITOR
2022-01-26 18:11:52 -05:00
}
} ;
2022-02-02 02:19:16 -05:00
/** Versions document from 1.8 to 1.9. */
class FVersionDocument_1_9 : public FVersionDocumentTransform
{
2022-02-10 15:07:39 -05:00
FName Name ;
const FString & Path ;
2022-02-02 02:19:16 -05:00
public :
2022-02-10 15:07:39 -05:00
FVersionDocument_1_9 ( FName InName , const FString & InPath )
: Name ( InName )
, Path ( InPath )
{
}
2022-02-02 02:19:16 -05:00
FMetasoundFrontendVersionNumber GetTargetVersion ( ) const override
{
return { 1 , 9 } ;
}
void TransformInternal ( FDocumentHandle InDocument ) const override
{
2022-02-10 15:07:39 -05:00
# if WITH_EDITOR
2022-02-02 02:19:16 -05:00
// Display name text is no longer copied at this versioning point for assets
// from the asset's FName to avoid FText warnings regarding generation from
// an FString. It also avoids desync if asset gets moved.
FMetasoundFrontendGraphClass RootGraphClass = InDocument - > GetRootGraphClass ( ) ;
RootGraphClass . Metadata . SetDisplayName ( FText ( ) ) ;
InDocument - > SetRootGraphClass ( MoveTemp ( RootGraphClass ) ) ;
2022-02-10 15:07:39 -05:00
# else
UE_LOG ( LogMetaSound , Error , TEXT ( " Asset '%s' at '%s' must be saved with editor enabled in order to version document to target version '%s'. " ) , * Name . ToString ( ) , * Path , * GetTargetVersion ( ) . ToString ( ) ) ;
# endif // !WITH_EDITOR
2022-02-02 02:19:16 -05:00
}
} ;
2022-02-09 12:52:07 -05:00
/** Versions document from 1.9 to 1.10. */
class FVersionDocument_1_10 : public FVersionDocumentTransform
{
public :
FVersionDocument_1_10 ( ) = default ;
FMetasoundFrontendVersionNumber GetTargetVersion ( ) const override
{
return { 1 , 10 } ;
}
void TransformInternal ( FDocumentHandle InDocument ) const override
{
FMetasoundFrontendGraphClass Class = InDocument - > GetRootGraphClass ( ) ;
FMetasoundFrontendGraphClassPresetOptions PresetOptions = Class . PresetOptions ;
Class . PresetOptions . bIsPreset = Class . Metadata . GetAndClearAutoUpdateManagesInterface_Deprecated ( ) ;
InDocument - > SetRootGraphClass ( MoveTemp ( Class ) ) ;
}
} ;
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.
2022-02-10 15:07:39 -05:00
bWasUpdated | = FVersionDocument_1_1 ( Name , Path ) . 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 ) ;
2022-02-10 15:07:39 -05:00
bWasUpdated | = FVersionDocument_1_5 ( Name , Path ) . Transform ( InDocument ) ;
2021-07-27 20:30:14 -04:00
bWasUpdated | = FVersionDocument_1_6 ( ) . Transform ( InDocument ) ;
2022-02-10 15:07:39 -05:00
bWasUpdated | = FVersionDocument_1_7 ( Name , Path ) . Transform ( InDocument ) ;
bWasUpdated | = FVersionDocument_1_8 ( Name , Path ) . Transform ( InDocument ) ;
bWasUpdated | = FVersionDocument_1_9 ( Name , Path ) . Transform ( InDocument ) ;
2022-02-09 12:52:07 -05:00
bWasUpdated | = FVersionDocument_1_10 ( ) . Transform ( InDocument ) ;
2021-07-27 20:30:14 -04:00
if ( bWasUpdated )
{
const FMetasoundFrontendVersionNumber NewVersionNumber = InDocument - > GetMetadata ( ) . Version . Number ;
2022-02-02 02:19:16 -05:00
UE_LOG ( LogMetaSound , Display , TEXT ( " MetaSound at '%s' Document Versioned: '%s' --> '%s' " ) , * Path , * InitVersionNumber . ToString ( ) , * NewVersionNumber . ToString ( ) ) ;
2021-07-27 20:30:14 -04:00
}
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