2021-11-07 23:43:01 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "MetasoundAssetSubsystem.h"
2021-11-22 15:55:50 -05:00
# include "Algo/Sort.h"
2021-11-07 23:43:01 -05:00
# include "Algo/Transform.h"
# include "AssetRegistry/AssetRegistryModule.h"
# include "Async/Async.h"
# include "Engine/AssetManager.h"
# include "Metasound.h"
# include "MetasoundAssetBase.h"
2023-06-16 17:55:08 -04:00
# include "MetasoundBuilderSubsystem.h"
2021-11-22 15:55:50 -05:00
# include "MetasoundFrontendDocument.h"
2021-11-07 23:43:01 -05:00
# include "MetasoundFrontendRegistries.h"
# include "MetasoundFrontendTransform.h"
# include "MetasoundSettings.h"
# include "MetasoundSource.h"
# include "MetasoundTrace.h"
2021-11-22 15:55:50 -05:00
# include "MetasoundUObjectRegistry.h"
2022-10-26 12:57:32 -04:00
# include "Misc/CoreDelegates.h"
2021-11-18 14:37:34 -05:00
# include "UObject/NoExportTypes.h"
2021-11-07 23:43:01 -05:00
2023-06-16 17:55:08 -04:00
2022-09-28 01:06:15 -04:00
# include UE_INLINE_GENERATED_CPP_BY_NAME(MetasoundAssetSubsystem)
2021-11-07 23:43:01 -05:00
namespace Metasound
{
namespace AssetSubsystemPrivate
{
bool GetAssetClassInfo ( const FAssetData & InAssetData , Frontend : : FNodeClassInfo & OutInfo )
{
using namespace Metasound ;
using namespace Metasound : : Frontend ;
bool bSuccess = true ;
OutInfo . Type = EMetasoundFrontendClassType : : External ;
2022-09-12 19:52:49 -04:00
OutInfo . AssetPath = InAssetData . GetSoftObjectPath ( ) ;
2021-11-07 23:43:01 -05:00
FString AssetClassID ;
bSuccess & = InAssetData . GetTagValue ( AssetTags : : AssetClassID , AssetClassID ) ;
OutInfo . AssetClassID = FGuid ( AssetClassID ) ;
OutInfo . ClassName = FMetasoundFrontendClassName ( FName ( ) , * AssetClassID , FName ( ) ) ;
2022-10-26 15:28:04 -04:00
# if WITH_EDITORONLY_DATA
InAssetData . GetTagValue ( AssetTags : : IsPreset , OutInfo . bIsPreset ) ;
# endif // WITH_EDITORONLY_DATA
2021-11-07 23:43:01 -05:00
int32 RegistryVersionMajor = 0 ;
bSuccess & = InAssetData . GetTagValue ( AssetTags : : RegistryVersionMajor , RegistryVersionMajor ) ;
OutInfo . Version . Major = RegistryVersionMajor ;
int32 RegistryVersionMinor = 0 ;
bSuccess & = InAssetData . GetTagValue ( AssetTags : : RegistryVersionMinor , RegistryVersionMinor ) ;
OutInfo . Version . Minor = RegistryVersionMinor ;
# if WITH_EDITORONLY_DATA
auto ParseTypesString = [ & ] ( const FName AssetTag , TSet < FName > & OutTypes )
{
FString TypesString ;
if ( InAssetData . GetTagValue ( AssetTag , TypesString ) )
{
TArray < FString > DataTypeStrings ;
TypesString . ParseIntoArray ( DataTypeStrings , * AssetTags : : ArrayDelim ) ;
Algo : : Transform ( DataTypeStrings , OutTypes , [ ] ( const FString & DataType ) { return * DataType ; } ) ;
return true ;
}
return false ;
} ;
2021-11-22 16:49:35 -05:00
// These values are optional and not necessary to return successfully as MetaSounds
// don't require inputs or outputs for asset tags to be valid (ex. a new MetaSound,
// non-source asset has no inputs or outputs)
2021-11-07 23:43:01 -05:00
OutInfo . InputTypes . Reset ( ) ;
2021-11-22 16:49:35 -05:00
ParseTypesString ( AssetTags : : RegistryInputTypes , OutInfo . InputTypes ) ;
2021-11-07 23:43:01 -05:00
OutInfo . OutputTypes . Reset ( ) ;
2021-11-22 16:49:35 -05:00
ParseTypesString ( AssetTags : : RegistryOutputTypes , OutInfo . OutputTypes ) ;
2021-11-07 23:43:01 -05:00
# endif // WITH_EDITORONLY_DATA
return bSuccess ;
}
2023-01-10 15:23:40 -05:00
// Remove the Map entry only if the key and value are equal.
//
// This protects against scenarios where a metasound is renamed or moved
// and the new entry was being erroneously removed from the PathMap
bool RemoveIfExactMatch ( TMap < Frontend : : FNodeRegistryKey , FSoftObjectPath > & InMap , const Frontend : : FNodeRegistryKey & InKeyToRemove , const FSoftObjectPath & InPathToRemove )
{
if ( const FSoftObjectPath * Path = InMap . Find ( InKeyToRemove ) )
{
if ( * Path = = InPathToRemove )
{
InMap . Remove ( InKeyToRemove ) ;
return true ;
}
else
{
UE_LOG ( LogMetaSound , VeryVerbose , TEXT ( " Object paths do not match. Skipping removal of %s:%s from the asset subsystem. " ) , * InKeyToRemove , * InPathToRemove . ToString ( ) ) ;
}
}
return false ;
}
2021-11-07 23:43:01 -05:00
}
}
void UMetaSoundAssetSubsystem : : Initialize ( FSubsystemCollectionBase & InCollection )
{
using namespace Metasound : : Frontend ;
IMetaSoundAssetManager : : Set ( * this ) ;
FCoreDelegates : : OnPostEngineInit . AddUObject ( this , & UMetaSoundAssetSubsystem : : PostEngineInit ) ;
}
void UMetaSoundAssetSubsystem : : PostEngineInit ( )
{
2023-03-02 19:37:50 -05:00
check ( UAssetManager : : IsInitialized ( ) ) ;
UAssetManager & AssetManager = UAssetManager : : Get ( ) ;
AssetManager . CallOrRegister_OnCompletedInitialScan ( FSimpleMulticastDelegate : : FDelegate : : CreateUObject ( this , & UMetaSoundAssetSubsystem : : PostInitAssetScan ) ) ;
RebuildDenyListCache ( AssetManager ) ;
2021-11-07 23:43:01 -05:00
}
void UMetaSoundAssetSubsystem : : PostInitAssetScan ( )
{
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( UMetaSoundAssetSubsystem : : PostInitAssetScan ) ;
2021-11-18 14:37:34 -05:00
const UMetaSoundSettings * Settings = GetDefault < UMetaSoundSettings > ( ) ;
if ( ensureAlways ( Settings ) )
2021-11-07 23:43:01 -05:00
{
2021-11-18 14:37:34 -05:00
SearchAndIterateDirectoryAssets ( Settings - > DirectoriesToRegister , [ this ] ( const FAssetData & AssetData )
{
2021-12-10 20:37:31 -05:00
AddOrUpdateAsset ( AssetData ) ;
2021-11-18 14:37:34 -05:00
} ) ;
2021-11-07 23:43:01 -05:00
}
2022-10-13 17:38:11 -04:00
bIsInitialAssetScanComplete = true ;
2021-11-07 23:43:01 -05:00
}
2022-10-13 17:38:11 -04:00
# if WITH_EDITORONLY_DATA
2021-11-24 16:44:58 -05:00
void UMetaSoundAssetSubsystem : : AddAssetReferences ( FMetasoundAssetBase & InAssetBase )
2021-11-07 23:43:01 -05:00
{
using namespace Metasound ;
using namespace Metasound : : Frontend ;
2021-11-24 16:44:58 -05:00
const FNodeClassInfo AssetClassInfo = InAssetBase . GetAssetClassInfo ( ) ;
const FNodeRegistryKey AssetClassKey = NodeRegistryKey : : CreateKey ( AssetClassInfo ) ;
if ( ! ContainsKey ( AssetClassKey ) )
2021-11-07 23:43:01 -05:00
{
2021-12-10 20:37:31 -05:00
AddOrUpdateAsset ( * InAssetBase . GetOwningAsset ( ) ) ;
UE_LOG ( LogMetaSound , Verbose , TEXT ( " Adding asset '%s' to MetaSoundAsset registry. " ) , * InAssetBase . GetOwningAssetName ( ) ) ;
2021-11-24 16:44:58 -05:00
}
2022-10-13 17:38:11 -04:00
bool bAddFromReferencedAssets = false ;
2021-11-24 16:44:58 -05:00
const TSet < FString > & ReferencedAssetClassKeys = InAssetBase . GetReferencedAssetClassKeys ( ) ;
for ( const FString & ReferencedAssetClassKey : ReferencedAssetClassKeys )
{
if ( ! ContainsKey ( ReferencedAssetClassKey ) )
2021-11-07 23:43:01 -05:00
{
2022-01-31 15:27:41 -05:00
UE_LOG ( LogMetaSound , Verbose , TEXT ( " Missing referenced class '%s' asset entry. " ) , * ReferencedAssetClassKey ) ;
2022-10-13 17:38:11 -04:00
bAddFromReferencedAssets = true ;
2021-11-07 23:43:01 -05:00
}
}
// All keys are loaded
2022-10-13 17:38:11 -04:00
if ( ! bAddFromReferencedAssets )
2021-11-07 23:43:01 -05:00
{
return ;
}
2022-01-31 15:27:41 -05:00
UE_LOG ( LogMetaSound , Verbose , TEXT ( " Attempting preemptive reference load... " ) ) ;
2021-11-07 23:43:01 -05:00
2022-10-13 17:38:11 -04:00
TArray < FMetasoundAssetBase * > ReferencedAssets = InAssetBase . GetReferencedAssets ( ) ;
for ( FMetasoundAssetBase * Asset : ReferencedAssets )
2021-11-07 23:43:01 -05:00
{
2022-10-13 17:38:11 -04:00
if ( Asset )
2021-11-07 23:43:01 -05:00
{
2022-10-13 17:38:11 -04:00
FNodeClassInfo ClassInfo = Asset - > GetAssetClassInfo ( ) ;
2021-11-07 23:43:01 -05:00
const FNodeRegistryKey ClassKey = NodeRegistryKey : : CreateKey ( ClassInfo ) ;
if ( ! ContainsKey ( ClassKey ) )
{
2022-01-31 15:27:41 -05:00
UE_LOG ( LogMetaSound , Verbose ,
2022-10-13 17:38:11 -04:00
TEXT ( " Preemptive load of class '%s' due to early "
2021-11-07 23:43:01 -05:00
" registration request (asset scan likely not complete). " ) ,
2022-10-13 17:38:11 -04:00
* ClassKey ) ;
2021-11-07 23:43:01 -05:00
2022-10-13 17:38:11 -04:00
UObject * MetaSoundObject = Asset - > GetOwningAsset ( ) ;
2021-11-07 23:43:01 -05:00
if ( ensureAlways ( MetaSoundObject ) )
{
2021-12-10 20:37:31 -05:00
AddOrUpdateAsset ( * MetaSoundObject ) ;
2021-11-07 23:43:01 -05:00
}
}
}
2022-10-13 17:38:11 -04:00
else
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Null referenced dependent asset in %s. Resaving asset in editor may fix the issue " ) , * InAssetBase . GetOwningAssetName ( ) ) ;
}
2021-11-07 23:43:01 -05:00
}
}
2022-10-13 17:38:11 -04:00
# endif
2021-11-07 23:43:01 -05:00
2022-02-09 12:52:44 -05:00
Metasound : : Frontend : : FNodeRegistryKey UMetaSoundAssetSubsystem : : AddOrUpdateAsset ( const UObject & InObject )
2021-11-07 23:43:01 -05:00
{
using namespace Metasound ;
using namespace Metasound : : AssetSubsystemPrivate ;
using namespace Metasound : : Frontend ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( UMetaSoundAssetSubsystem : : AddOrUpdateAsset ) ;
2022-02-09 12:52:44 -05:00
const FMetasoundAssetBase * MetaSoundAsset = Metasound : : IMetasoundUObjectRegistry : : Get ( ) . GetObjectAsAssetBase ( & InObject ) ;
2021-11-07 23:43:01 -05:00
check ( MetaSoundAsset ) ;
FNodeClassInfo ClassInfo = MetaSoundAsset - > GetAssetClassInfo ( ) ;
const FNodeRegistryKey RegistryKey = NodeRegistryKey : : CreateKey ( ClassInfo ) ;
2022-03-10 21:19:13 -05:00
if ( NodeRegistryKey : : IsValid ( RegistryKey ) )
{
PathMap . FindOrAdd ( RegistryKey ) = InObject . GetPathName ( ) ;
}
2022-02-09 12:52:44 -05:00
return RegistryKey ;
2021-11-07 23:43:01 -05:00
}
2022-02-09 12:52:44 -05:00
Metasound : : Frontend : : FNodeRegistryKey UMetaSoundAssetSubsystem : : AddOrUpdateAsset ( const FAssetData & InAssetData )
2021-11-07 23:43:01 -05:00
{
using namespace Metasound ;
using namespace Metasound : : AssetSubsystemPrivate ;
using namespace Metasound : : Frontend ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( UMetaSoundAssetSubsystem : : AddOrUpdateAsset ) ;
FNodeClassInfo ClassInfo ;
bool bClassInfoFound = GetAssetClassInfo ( InAssetData , ClassInfo ) ;
2021-12-10 20:37:31 -05:00
if ( ! bClassInfoFound )
2021-11-07 23:43:01 -05:00
{
UObject * Object = nullptr ;
2022-09-12 19:52:49 -04:00
FSoftObjectPath Path = InAssetData . ToSoftObjectPath ( ) ;
if ( ! FPackageName : : GetPackageMountPoint ( InAssetData . GetObjectPathString ( ) ) . IsNone ( ) )
2021-11-07 23:43:01 -05:00
{
2022-04-21 18:49:47 -04:00
if ( InAssetData . IsAssetLoaded ( ) )
{
Object = Path . ResolveObject ( ) ;
UE_LOG ( LogMetaSound , Verbose , TEXT ( " Adding loaded asset '%s' to MetaSoundAsset registry. " ) , * Object - > GetName ( ) ) ;
}
else
{
Object = Path . TryLoad ( ) ;
UE_LOG ( LogMetaSound , Verbose , TEXT ( " Loaded asset '%s' and adding to MetaSoundAsset registry. " ) , * Object - > GetName ( ) ) ;
}
2021-11-07 23:43:01 -05:00
}
if ( Object )
{
2022-02-09 12:52:44 -05:00
return AddOrUpdateAsset ( * Object ) ;
2021-11-07 23:43:01 -05:00
}
}
2022-03-10 21:19:13 -05:00
if ( ClassInfo . AssetClassID . IsValid ( ) )
{
const FNodeRegistryKey RegistryKey = NodeRegistryKey : : CreateKey ( ClassInfo ) ;
if ( NodeRegistryKey : : IsValid ( RegistryKey ) )
{
2022-09-12 19:52:49 -04:00
PathMap . FindOrAdd ( RegistryKey ) = InAssetData . GetSoftObjectPath ( ) ;
2022-03-10 21:19:13 -05:00
}
2022-02-09 12:52:44 -05:00
2022-03-10 21:19:13 -05:00
return RegistryKey ;
}
// Invalid ClassID means the node could not be registered.
// Let caller report or ensure as necessary.
return NodeRegistryKey : : GetInvalid ( ) ;
2021-11-07 23:43:01 -05:00
}
bool UMetaSoundAssetSubsystem : : CanAutoUpdate ( const FMetasoundFrontendClassName & InClassName ) const
{
const UMetaSoundSettings * Settings = GetDefault < UMetaSoundSettings > ( ) ;
if ( ! Settings - > bAutoUpdateEnabled )
{
return false ;
}
return ! AutoUpdateDenyListCache . Contains ( InClassName . GetFullName ( ) ) ;
}
bool UMetaSoundAssetSubsystem : : ContainsKey ( const Metasound : : Frontend : : FNodeRegistryKey & InRegistryKey ) const
{
return PathMap . Contains ( InRegistryKey ) ;
}
void UMetaSoundAssetSubsystem : : RebuildDenyListCache ( const UAssetManager & InAssetManager )
{
using namespace Metasound : : Frontend ;
const UMetaSoundSettings * Settings = GetDefault < UMetaSoundSettings > ( ) ;
if ( Settings - > DenyListCacheChangeID = = AutoUpdateDenyListChangeID )
{
return ;
}
AutoUpdateDenyListCache . Reset ( ) ;
2021-12-13 13:15:05 -05:00
for ( const FMetasoundFrontendClassName & ClassName : Settings - > AutoUpdateDenylist )
2021-11-07 23:43:01 -05:00
{
AutoUpdateDenyListCache . Add ( ClassName . GetFullName ( ) ) ;
}
2023-03-02 19:37:50 -05:00
check ( UAssetManager : : IsInitialized ( ) ) ;
UAssetManager & AssetManager = UAssetManager : : Get ( ) ;
2021-12-13 13:15:05 -05:00
for ( const FDefaultMetaSoundAssetAutoUpdateSettings & UpdateSettings : Settings - > AutoUpdateAssetDenylist )
2021-11-07 23:43:01 -05:00
{
2023-03-02 19:37:50 -05:00
FAssetData AssetData ;
if ( AssetManager . GetAssetDataForPath ( UpdateSettings . MetaSound , AssetData ) )
2021-11-07 23:43:01 -05:00
{
2023-03-02 19:37:50 -05:00
FString AssetClassID ;
if ( AssetData . GetTagValue ( AssetTags : : AssetClassID , AssetClassID ) )
2021-11-07 23:43:01 -05:00
{
2023-03-02 19:37:50 -05:00
const FMetasoundFrontendClassName ClassName = { FName ( ) , * AssetClassID , FName ( ) } ;
AutoUpdateDenyListCache . Add ( ClassName . GetFullName ( ) ) ;
2021-11-07 23:43:01 -05:00
}
}
}
AutoUpdateDenyListChangeID = Settings - > DenyListCacheChangeID ;
}
2022-10-13 17:38:11 -04:00
# if WITH_EDITOR
TSet < UMetaSoundAssetSubsystem : : FAssetInfo > UMetaSoundAssetSubsystem : : GetReferencedAssetClasses ( const FMetasoundAssetBase & InAssetBase ) const
2021-11-07 23:43:01 -05:00
{
2022-10-13 17:38:11 -04:00
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( UMetaSoundAssetSubsystem : : GetReferencedAssetClasses ) ;
2021-11-07 23:43:01 -05:00
using namespace Metasound : : Frontend ;
2022-10-13 17:38:11 -04:00
TSet < FAssetInfo > OutAssetInfos ;
2021-11-07 23:43:01 -05:00
const FMetasoundFrontendDocument & Document = InAssetBase . GetDocumentChecked ( ) ;
for ( const FMetasoundFrontendClass & Class : Document . Dependencies )
{
const FNodeRegistryKey Key = NodeRegistryKey : : CreateKey ( Class . Metadata ) ;
2022-10-13 17:38:11 -04:00
if ( const FSoftObjectPath * ObjectPath = PathMap . Find ( Key ) )
2021-11-07 23:43:01 -05:00
{
2022-10-13 17:38:11 -04:00
OutAssetInfos . Add ( FAssetInfo { Key , * ObjectPath } ) ;
2021-11-07 23:43:01 -05:00
}
2023-08-07 16:58:38 -04:00
else
{
const FMetasoundFrontendRegistryContainer * Registry = FMetasoundFrontendRegistryContainer : : Get ( ) ;
check ( Registry ) ;
const bool bIsRegistered = Registry - > IsNodeRegistered ( Key ) ;
bool bReportFail = false ;
if ( bIsRegistered )
{
if ( ! Registry - > IsNodeNative ( Key ) )
{
bReportFail = true ;
}
}
else
{
bReportFail = true ;
}
if ( bReportFail )
{
if ( bIsInitialAssetScanComplete )
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " MetaSound Node Class with registry key '%s' not registered when gathering referenced asset classes from '%s': Retrieving all asset classes may not be comprehensive. " ) , * Key , * InAssetBase . GetOwningAssetName ( ) ) ;
}
else
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Attempt to get registered dependent asset with key '%s' from MetaSound asset '%s' before asset scan has completed: Asset class cannot be provided " ) , * Key , * InAssetBase . GetOwningAssetName ( ) ) ;
}
}
}
2021-11-07 23:43:01 -05:00
}
2022-10-13 17:38:11 -04:00
return MoveTemp ( OutAssetInfos ) ;
2021-11-07 23:43:01 -05:00
}
2022-10-13 17:38:11 -04:00
# endif
2021-11-07 23:43:01 -05:00
void UMetaSoundAssetSubsystem : : RescanAutoUpdateDenyList ( )
{
2023-03-02 19:37:50 -05:00
check ( UAssetManager : : IsInitialized ( ) ) ;
RebuildDenyListCache ( UAssetManager : : Get ( ) ) ;
2021-11-07 23:43:01 -05:00
}
FMetasoundAssetBase * UMetaSoundAssetSubsystem : : TryLoadAssetFromKey ( const Metasound : : Frontend : : FNodeRegistryKey & RegistryKey ) const
{
if ( const FSoftObjectPath * ObjectPath = FindObjectPathFromKey ( RegistryKey ) )
{
return TryLoadAsset ( * ObjectPath ) ;
}
return nullptr ;
}
bool UMetaSoundAssetSubsystem : : TryLoadReferencedAssets ( const FMetasoundAssetBase & InAssetBase , TArray < FMetasoundAssetBase * > & OutReferencedAssets ) const
{
using namespace Metasound : : Frontend ;
bool bSucceeded = true ;
OutReferencedAssets . Reset ( ) ;
TArray < FMetasoundAssetBase * > ReferencedAssets ;
const TSet < FString > & AssetClassKeys = InAssetBase . GetReferencedAssetClassKeys ( ) ;
for ( const FNodeRegistryKey & Key : AssetClassKeys )
{
if ( FMetasoundAssetBase * MetaSound = TryLoadAssetFromKey ( Key ) )
{
OutReferencedAssets . Add ( MetaSound ) ;
}
else
{
UE_LOG ( LogMetaSound , Error , TEXT ( " Failed to find referenced MetaSound asset with key '%s' " ) , * Key ) ;
bSucceeded = false ;
}
}
return bSucceeded ;
}
2022-10-13 17:38:11 -04:00
void UMetaSoundAssetSubsystem : : RequestAsyncLoadReferencedAssets ( FMetasoundAssetBase & InAssetBase )
{
const TSet < FSoftObjectPath > & AsyncReferences = InAssetBase . GetAsyncReferencedAssetClassPaths ( ) ;
if ( AsyncReferences . Num ( ) > 0 )
{
if ( UObject * OwningAsset = InAssetBase . GetOwningAsset ( ) )
{
TArray < FSoftObjectPath > PathsToLoad = AsyncReferences . Array ( ) ;
// Protect against duplicate calls to async load assets.
if ( FMetaSoundAsyncAssetDependencies * ExistingAsyncLoad = FindLoadingDependencies ( OwningAsset ) )
{
if ( ExistingAsyncLoad - > Dependencies = = PathsToLoad )
{
// early out since these are already actively being loaded.
return ;
}
}
int32 AsyncLoadID = AsyncLoadIDCounter + + ;
auto AssetsLoadedDelegate = [ this , AsyncLoadID ] ( )
{
this - > OnAssetsLoaded ( AsyncLoadID ) ;
} ;
// Store async loading data for use when async load is complete.
FMetaSoundAsyncAssetDependencies & AsyncDependencies = LoadingDependencies . AddDefaulted_GetRef ( ) ;
AsyncDependencies . LoadID = AsyncLoadID ;
AsyncDependencies . MetaSound = OwningAsset ;
AsyncDependencies . Dependencies = PathsToLoad ;
AsyncDependencies . StreamableHandle = StreamableManager . RequestAsyncLoad ( PathsToLoad , AssetsLoadedDelegate ) ;
}
else
{
UE_LOG ( LogMetaSound , Error , TEXT ( " Cannot load async asset as FMetasoundAssetBase null owning UObject " ) , * InAssetBase . GetOwningAssetName ( ) ) ;
}
}
}
void UMetaSoundAssetSubsystem : : WaitUntilAsyncLoadReferencedAssetsComplete ( FMetasoundAssetBase & InAssetBase )
{
2022-11-17 12:31:19 -05:00
TSet < FMetasoundAssetBase * > TransitiveReferences ;
TArray < FMetasoundAssetBase * > TransitiveReferencesQueue ;
TransitiveReferences . Add ( & InAssetBase ) ;
TransitiveReferencesQueue . Add ( & InAssetBase ) ;
while ( ! TransitiveReferencesQueue . IsEmpty ( ) )
2022-10-13 17:38:11 -04:00
{
2022-11-17 12:31:19 -05:00
FMetasoundAssetBase * Reference = TransitiveReferencesQueue . Pop ( ) ;
UObject * OwningAsset = Reference - > GetOwningAsset ( ) ;
if ( ! OwningAsset )
{
continue ;
}
2022-10-13 17:38:11 -04:00
while ( FMetaSoundAsyncAssetDependencies * LoadingDependency = FindLoadingDependencies ( OwningAsset ) )
{
// Grab shared ptr to handle as LoadingDependencies may be deleted and have it's shared pointer removed.
TSharedPtr < FStreamableHandle > StreamableHandle = LoadingDependency - > StreamableHandle ;
if ( StreamableHandle . IsValid ( ) )
{
UE_LOG ( LogMetaSound , Verbose , TEXT ( " Waiting on async load (id: %d) from asset %s " ) , LoadingDependency - > LoadID , * InAssetBase . GetOwningAssetName ( ) ) ;
EAsyncPackageState : : Type LoadState = StreamableHandle - > WaitUntilComplete ( ) ;
if ( EAsyncPackageState : : Complete ! = LoadState )
{
UE_LOG ( LogMetaSound , Error , TEXT ( " Failed to complete loading of async dependent assets from parent asset %s " ) , * InAssetBase . GetOwningAssetName ( ) ) ;
RemoveLoadingDependencies ( LoadingDependency - > LoadID ) ;
}
else
{
// This will remove the loading dependencies from internal storage
OnAssetsLoaded ( LoadingDependency - > LoadID ) ;
}
// This will prevent OnAssetsLoaded from being called via the streamables
// internal delegate complete callback.
StreamableHandle - > CancelHandle ( ) ;
}
}
2022-11-17 12:31:19 -05:00
for ( FMetasoundAssetBase * NextReference : Reference - > GetReferencedAssets ( ) )
{
bool bAlreadyInSet ;
TransitiveReferences . Add ( NextReference , & bAlreadyInSet ) ;
if ( ! bAlreadyInSet )
{
TransitiveReferencesQueue . Add ( NextReference ) ;
}
}
2022-10-13 17:38:11 -04:00
}
}
FMetaSoundAsyncAssetDependencies * UMetaSoundAssetSubsystem : : FindLoadingDependencies ( const UObject * InParentAsset )
{
auto IsEqualMetaSoundUObject = [ InParentAsset ] ( const FMetaSoundAsyncAssetDependencies & InDependencies ) - > bool
{
return ( InDependencies . MetaSound = = InParentAsset ) ;
} ;
return LoadingDependencies . FindByPredicate ( IsEqualMetaSoundUObject ) ;
}
FMetaSoundAsyncAssetDependencies * UMetaSoundAssetSubsystem : : FindLoadingDependencies ( int32 InLoadID )
{
auto IsEqualID = [ InLoadID ] ( const FMetaSoundAsyncAssetDependencies & InDependencies ) - > bool
{
return ( InDependencies . LoadID = = InLoadID ) ;
} ;
return LoadingDependencies . FindByPredicate ( IsEqualID ) ;
}
void UMetaSoundAssetSubsystem : : RemoveLoadingDependencies ( int32 InLoadID )
{
auto IsEqualID = [ InLoadID ] ( const FMetaSoundAsyncAssetDependencies & InDependencies ) - > bool
{
return ( InDependencies . LoadID = = InLoadID ) ;
} ;
LoadingDependencies . RemoveAllSwap ( IsEqualID ) ;
}
void UMetaSoundAssetSubsystem : : OnAssetsLoaded ( int32 InLoadID )
{
FMetaSoundAsyncAssetDependencies * LoadedDependencies = FindLoadingDependencies ( InLoadID ) ;
if ( ensureMsgf ( LoadedDependencies , TEXT ( " Call to async asset load complete with invalid IDs %d " ) , InLoadID ) )
{
if ( LoadedDependencies - > StreamableHandle . IsValid ( ) )
{
if ( LoadedDependencies - > MetaSound )
{
Metasound : : IMetasoundUObjectRegistry & UObjectRegistry = Metasound : : IMetasoundUObjectRegistry : : Get ( ) ;
FMetasoundAssetBase * ParentAssetBase = UObjectRegistry . GetObjectAsAssetBase ( LoadedDependencies - > MetaSound ) ;
if ( ensureMsgf ( ParentAssetBase , TEXT ( " UClass of Parent MetaSound asset %s is not registered in metasound UObject Registery " ) , * LoadedDependencies - > MetaSound - > GetPathName ( ) ) )
{
// Get all async loaded assets
TArray < UObject * > LoadedAssets ;
LoadedDependencies - > StreamableHandle - > GetLoadedAssets ( LoadedAssets ) ;
// Cast UObjects to FMetaSoundAssetBase
TArray < FMetasoundAssetBase * > LoadedAssetBases ;
for ( UObject * AssetDependency : LoadedAssets )
{
if ( AssetDependency )
{
FMetasoundAssetBase * AssetDependencyBase = UObjectRegistry . GetObjectAsAssetBase ( AssetDependency ) ;
if ( ensure ( AssetDependencyBase ) )
{
LoadedAssetBases . Add ( AssetDependencyBase ) ;
}
}
}
// Update parent asset with loaded assets.
ParentAssetBase - > OnAsyncReferencedAssetsLoaded ( LoadedAssetBases ) ;
}
}
}
// Remove from active array of loading dependencies.
RemoveLoadingDependencies ( InLoadID ) ;
}
}
2021-11-07 23:43:01 -05:00
const FSoftObjectPath * UMetaSoundAssetSubsystem : : FindObjectPathFromKey ( const Metasound : : Frontend : : FNodeRegistryKey & InRegistryKey ) const
{
return PathMap . Find ( InRegistryKey ) ;
}
FMetasoundAssetBase * UMetaSoundAssetSubsystem : : TryLoadAsset ( const FSoftObjectPath & InObjectPath ) const
{
return Metasound : : IMetasoundUObjectRegistry : : Get ( ) . GetObjectAsAssetBase ( InObjectPath . TryLoad ( ) ) ;
}
2022-02-09 12:52:44 -05:00
void UMetaSoundAssetSubsystem : : RemoveAsset ( const UObject & InObject )
2021-11-07 23:43:01 -05:00
{
using namespace Metasound ;
using namespace Metasound : : Frontend ;
2022-02-09 12:52:44 -05:00
if ( const FMetasoundAssetBase * MetaSoundAsset = Metasound : : IMetasoundUObjectRegistry : : Get ( ) . GetObjectAsAssetBase ( & InObject ) )
2021-11-07 23:43:01 -05:00
{
const FNodeClassInfo ClassInfo = MetaSoundAsset - > GetAssetClassInfo ( ) ;
FNodeRegistryKey RegistryKey = FMetasoundFrontendRegistryContainer : : Get ( ) - > GetRegistryKey ( ClassInfo ) ;
2023-06-16 17:55:08 -04:00
const FSoftObjectPath ObjectPath ( & InObject ) ;
if ( AssetSubsystemPrivate : : RemoveIfExactMatch ( PathMap , RegistryKey , ObjectPath ) )
{
UMetaSoundBuilderSubsystem : : GetChecked ( ) . DetachBuilderFromAsset ( ClassInfo . ClassName ) ;
}
2021-11-07 23:43:01 -05:00
}
}
2021-12-10 20:37:31 -05:00
void UMetaSoundAssetSubsystem : : RemoveAsset ( const FAssetData & InAssetData )
2021-11-07 23:43:01 -05:00
{
using namespace Metasound ;
using namespace Metasound : : Frontend ;
FNodeClassInfo ClassInfo ;
if ( ensureAlways ( AssetSubsystemPrivate : : GetAssetClassInfo ( InAssetData , ClassInfo ) ) )
{
FNodeRegistryKey RegistryKey = FMetasoundFrontendRegistryContainer : : Get ( ) - > GetRegistryKey ( ClassInfo ) ;
2023-06-16 17:55:08 -04:00
const FSoftObjectPath ObjectPath = InAssetData . GetSoftObjectPath ( ) ;
if ( AssetSubsystemPrivate : : RemoveIfExactMatch ( PathMap , RegistryKey , ObjectPath ) )
{
UMetaSoundBuilderSubsystem : : GetChecked ( ) . DetachBuilderFromAsset ( ClassInfo . ClassName ) ;
}
2021-11-07 23:43:01 -05:00
}
}
void UMetaSoundAssetSubsystem : : RenameAsset ( const FAssetData & InAssetData , bool bInReregisterWithFrontend )
{
2021-12-10 20:37:31 -05:00
auto PerformRename = [ this , & InAssetData ] ( )
{
RemoveAsset ( InAssetData ) ;
2022-02-02 02:19:16 -05:00
ResetAssetClassDisplayName ( InAssetData ) ;
2021-12-10 20:37:31 -05:00
AddOrUpdateAsset ( InAssetData ) ;
} ;
if ( bInReregisterWithFrontend )
{
FMetasoundAssetBase * MetaSoundAsset = Metasound : : IMetasoundUObjectRegistry : : Get ( ) . GetObjectAsAssetBase ( InAssetData . GetAsset ( ) ) ;
check ( MetaSoundAsset ) ;
MetaSoundAsset - > UnregisterGraphWithFrontend ( ) ;
PerformRename ( ) ;
MetaSoundAsset - > RegisterGraphWithFrontend ( ) ;
}
else
{
PerformRename ( ) ;
}
2021-11-07 23:43:01 -05:00
}
2022-02-02 02:19:16 -05:00
void UMetaSoundAssetSubsystem : : ResetAssetClassDisplayName ( const FAssetData & InAssetData )
2021-11-07 23:43:01 -05:00
{
UObject * Object = nullptr ;
2022-09-12 19:52:49 -04:00
FSoftObjectPath Path = InAssetData . GetSoftObjectPath ( ) ;
2021-11-07 23:43:01 -05:00
if ( InAssetData . IsAssetLoaded ( ) )
{
Object = Path . ResolveObject ( ) ;
}
else
{
Object = Path . TryLoad ( ) ;
}
FMetasoundAssetBase * MetaSoundAsset = Metasound : : IMetasoundUObjectRegistry : : Get ( ) . GetObjectAsAssetBase ( Object ) ;
check ( MetaSoundAsset ) ;
2022-02-02 02:19:16 -05:00
FMetasoundFrontendGraphClass & Class = MetaSoundAsset - > GetDocumentChecked ( ) . RootGraph ;
2022-02-10 15:07:39 -05:00
# if WITH_EDITOR
2022-02-02 02:19:16 -05:00
Class . Metadata . SetDisplayName ( FText ( ) ) ;
2022-02-10 15:07:39 -05:00
# endif // WITH_EDITOR
2021-11-07 23:43:01 -05:00
}
2021-11-18 14:37:34 -05:00
void UMetaSoundAssetSubsystem : : SearchAndIterateDirectoryAssets ( const TArray < FDirectoryPath > & InDirectories , TFunctionRef < void ( const FAssetData & ) > InFunction )
{
if ( InDirectories . IsEmpty ( ) )
{
return ;
}
UAssetManager & AssetManager = UAssetManager : : Get ( ) ;
FAssetManagerSearchRules Rules ;
for ( const FDirectoryPath & Path : InDirectories )
{
Rules . AssetScanPaths . Add ( * Path . Path ) ;
}
2021-12-10 20:37:31 -05:00
Metasound : : IMetasoundUObjectRegistry : : Get ( ) . IterateRegisteredUClasses ( [ & ] ( UClass & RegisteredClass )
2021-11-18 14:37:34 -05:00
{
2021-12-10 20:37:31 -05:00
Rules . AssetBaseClass = & RegisteredClass ;
TArray < FAssetData > MetaSoundAssets ;
AssetManager . SearchAssetRegistryPaths ( MetaSoundAssets , Rules ) ;
for ( const FAssetData & AssetData : MetaSoundAssets )
{
InFunction ( AssetData ) ;
}
} ) ;
2021-11-18 14:37:34 -05:00
}
void UMetaSoundAssetSubsystem : : RegisterAssetClassesInDirectories ( const TArray < FMetaSoundAssetDirectory > & InDirectories )
{
TArray < FDirectoryPath > Directories ;
Algo : : Transform ( InDirectories , Directories , [ ] ( const FMetaSoundAssetDirectory & AssetDir ) { return AssetDir . Directory ; } ) ;
SearchAndIterateDirectoryAssets ( Directories , [ this ] ( const FAssetData & AssetData )
{
2021-12-10 20:37:31 -05:00
AddOrUpdateAsset ( AssetData ) ;
FMetasoundAssetBase * MetaSoundAsset = Metasound : : IMetasoundUObjectRegistry : : Get ( ) . GetObjectAsAssetBase ( AssetData . GetAsset ( ) ) ;
check ( MetaSoundAsset ) ;
2022-03-01 21:25:04 -05:00
Metasound : : Frontend : : FMetaSoundAssetRegistrationOptions RegOptions ;
if ( const UMetaSoundSettings * Settings = GetDefault < UMetaSoundSettings > ( ) )
{
RegOptions . bAutoUpdateLogWarningOnDroppedConnection = Settings - > bAutoUpdateLogWarningOnDroppedConnection ;
}
MetaSoundAsset - > RegisterGraphWithFrontend ( RegOptions ) ;
2021-11-18 14:37:34 -05:00
} ) ;
}
void UMetaSoundAssetSubsystem : : UnregisterAssetClassesInDirectories ( const TArray < FMetaSoundAssetDirectory > & InDirectories )
{
TArray < FDirectoryPath > Directories ;
Algo : : Transform ( InDirectories , Directories , [ ] ( const FMetaSoundAssetDirectory & AssetDir ) { return AssetDir . Directory ; } ) ;
SearchAndIterateDirectoryAssets ( Directories , [ this ] ( const FAssetData & AssetData )
{
2021-12-10 20:37:31 -05:00
using namespace Metasound ;
using namespace Metasound : : Frontend ;
if ( AssetData . IsAssetLoaded ( ) )
{
FMetasoundAssetBase * MetaSoundAsset = Metasound : : IMetasoundUObjectRegistry : : Get ( ) . GetObjectAsAssetBase ( AssetData . GetAsset ( ) ) ;
check ( MetaSoundAsset ) ;
MetaSoundAsset - > UnregisterGraphWithFrontend ( ) ;
RemoveAsset ( AssetData ) ;
}
else
{
FNodeClassInfo AssetClassInfo ;
if ( ensureAlways ( AssetSubsystemPrivate : : GetAssetClassInfo ( AssetData , AssetClassInfo ) ) )
{
const FNodeRegistryKey RegistryKey = NodeRegistryKey : : CreateKey ( AssetClassInfo ) ;
const bool bIsRegistered = FMetasoundFrontendRegistryContainer : : Get ( ) - > IsNodeRegistered ( RegistryKey ) ;
if ( bIsRegistered )
{
FMetasoundFrontendRegistryContainer : : Get ( ) - > UnregisterNode ( RegistryKey ) ;
2023-01-10 15:23:40 -05:00
AssetSubsystemPrivate : : RemoveIfExactMatch ( PathMap , RegistryKey , AssetData . GetSoftObjectPath ( ) ) ;
2021-12-10 20:37:31 -05:00
}
}
}
2021-11-18 14:37:34 -05:00
} ) ;
}
2022-09-28 01:06:15 -04:00