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"
2024-09-10 10:26:02 -04:00
# include "HAL/CriticalSection.h"
2021-11-07 23:43:01 -05:00
# include "Metasound.h"
# include "MetasoundAssetBase.h"
2023-06-16 17:48:20 -04:00
# include "MetasoundBuilderSubsystem.h"
2024-09-10 10:26:02 -04:00
# include "MetasoundDocumentBuilderRegistry.h"
2024-05-08 14:53:53 -04:00
# include "MetasoundEngineAsset.h"
2021-11-22 15:55:50 -05:00
# include "MetasoundFrontendDocument.h"
2024-01-31 17:59:29 -05:00
# include "MetasoundFrontendDocumentBuilder.h"
2021-11-07 23:43:01 -05:00
# include "MetasoundFrontendRegistries.h"
2023-12-14 19:12:32 -05:00
# include "MetasoundFrontendSearchEngine.h"
2021-11-07 23:43:01 -05:00
# 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"
2024-05-08 14:53:53 -04:00
# include "Modules/ModuleManager.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:48:20 -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
2024-05-08 14:53:53 -04:00
namespace Metasound : : Engine
2021-11-07 23:43:01 -05:00
{
namespace AssetSubsystemPrivate
{
bool GetAssetClassInfo ( const FAssetData & InAssetData , Frontend : : FNodeClassInfo & OutInfo )
{
using namespace Metasound ;
using namespace Metasound : : Frontend ;
bool bSuccess = true ;
OutInfo . Type = EMetasoundFrontendClassType : : External ;
2024-05-08 14:53:53 -04:00
OutInfo . AssetPath = FTopLevelAssetPath ( InAssetData . PackageName , InAssetData . AssetName ) ;
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
2024-09-10 10:26:02 -04:00
bool RemovePath ( FCriticalSection * MapCritSec , TMap < Frontend : : FAssetKey , TArray < FTopLevelAssetPath > > & Map , const Frontend : : FAssetKey & AssetKey , const FTopLevelAssetPath & AssetPath )
2023-01-10 15:23:40 -05:00
{
2024-09-10 10:26:02 -04:00
check ( MapCritSec ) ;
FScopeLock Lock ( MapCritSec ) ;
if ( TArray < FTopLevelAssetPath > * MapAssetPaths = Map . Find ( AssetKey ) )
2023-01-10 15:23:40 -05:00
{
2024-06-21 16:41:02 -04:00
auto ComparePaths = [ & AssetPath ] ( const FTopLevelAssetPath & Path )
{
// Compare full paths if valid
if ( Path . IsValid ( ) & & AssetPath . IsValid ( ) )
{
return Path = = AssetPath ;
}
// Package names are stripped on destruction, so only asset name is reliable
return Path . GetAssetName ( ) = = AssetPath . GetAssetName ( ) ;
} ;
2024-05-14 20:20:01 -04:00
if ( MapAssetPaths - > RemoveAllSwap ( ComparePaths , EAllowShrinking : : No ) > 0 )
2023-01-10 15:23:40 -05:00
{
2024-05-10 12:40:21 -04:00
if ( MapAssetPaths - > IsEmpty ( ) )
2024-05-08 14:53:53 -04:00
{
2024-09-10 10:26:02 -04:00
Map . Remove ( AssetKey ) ;
2024-05-08 14:53:53 -04:00
}
2024-05-14 20:20:01 -04:00
return true ;
2024-05-08 14:53:53 -04:00
}
}
2024-05-09 19:02:03 -04:00
2024-05-10 12:40:21 -04:00
return false ;
}
2024-09-10 10:26:02 -04:00
void AddPath ( FCriticalSection * MapCritSec , TMap < Frontend : : FAssetKey , TArray < FTopLevelAssetPath > > & Map , const Frontend : : FAssetKey & AssetKey , const FTopLevelAssetPath & AssetPath )
2024-05-10 12:40:21 -04:00
{
2024-09-10 10:26:02 -04:00
check ( MapCritSec ) ;
FScopeLock Lock ( MapCritSec ) ;
TArray < FTopLevelAssetPath > & Paths = Map . FindOrAdd ( AssetKey ) ;
2024-05-10 12:40:21 -04:00
Paths . AddUnique ( AssetPath ) ;
# if !NO_LOGGING
if ( Paths . Num ( ) > 1 )
{
TArray < FString > PathStrings ;
Algo : : Transform ( Paths , PathStrings , [ ] ( const FTopLevelAssetPath & Path ) { return Path . ToString ( ) ; } ) ;
UE_LOG ( LogMetaSound , Warning ,
TEXT ( " MetaSoundAssetManager has registered multiple assets with key '%s': \n %s \n " ) ,
* AssetKey . ToString ( ) ,
* FString : : Join ( PathStrings , TEXT ( " \n " ) ) ) ;
}
# endif // !NO_LOGGING
2024-05-09 14:13:09 -04:00
}
2024-05-08 14:53:53 -04:00
}
class FMetaSoundAssetManager :
public Frontend : : IMetaSoundAssetManager ,
public FGCObject
{
public :
using FAssetInfo = Frontend : : IMetaSoundAssetManager : : FAssetInfo ;
using FAssetKey = Frontend : : FAssetKey ;
FMetaSoundAssetManager ( ) = default ;
virtual ~ FMetaSoundAssetManager ( ) ;
static FMetaSoundAssetManager & GetChecked ( )
{
using namespace Frontend ;
return static_cast < FMetaSoundAssetManager & > ( IMetaSoundAssetManager : : GetChecked ( ) ) ;
}
void RebuildDenyListCache ( const UAssetManager & InAssetManager ) ;
void RegisterAssetClassesInDirectories ( const TArray < FMetaSoundAssetDirectory > & Directories ) ;
2024-09-10 10:26:02 -04:00
# if WITH_EDITOR
bool ReplaceReferencesInDirectory ( const TArray < FMetaSoundAssetDirectory > & InDirectories , const Metasound : : Frontend : : FNodeRegistryKey & OldClassKey , const Metasound : : Frontend : : FNodeRegistryKey & NewClassKey ) const ;
# endif // WITH_EDITOR
2024-05-08 14:53:53 -04:00
void RequestAsyncLoadReferencedAssets ( FMetasoundAssetBase & InAssetBase ) ;
void OnAssetScanComplete ( ) ;
2024-09-10 10:26:02 -04:00
void SearchAndIterateDirectoryAssets ( const TArray < FDirectoryPath > & InDirectories , TFunctionRef < void ( const FAssetData & ) > InFunction ) const ;
2024-05-08 14:53:53 -04:00
FMetasoundAssetBase * TryLoadAsset ( const FSoftObjectPath & InObjectPath ) const ;
void UnregisterAssetClassesInDirectories ( const TArray < FMetaSoundAssetDirectory > & Directories ) ;
/* IMetaSoundAssetManager Implementation */
# if WITH_EDITORONLY_DATA
2024-05-29 15:33:29 -04:00
virtual bool AddAssetReferences ( FMetasoundAssetBase & InAssetBase ) override ;
2024-05-08 14:53:53 -04:00
# endif // WITH_EDITORONLY_DATA
virtual FAssetKey AddOrUpdateAsset ( const FAssetData & InAssetData ) override ;
virtual FAssetKey AddOrUpdateAsset ( const UObject & InObject ) override ;
virtual bool CanAutoUpdate ( const FMetasoundFrontendClassName & InClassName ) const override ;
virtual bool ContainsKey ( const FAssetKey & InKey ) const override ;
virtual FMetasoundAssetBase * FindAsset ( const FAssetKey & InKey ) const override ;
virtual TScriptInterface < IMetaSoundDocumentInterface > FindAssetAsDocumentInterface ( const Frontend : : FAssetKey & InKey ) const override ;
2024-09-10 10:26:02 -04:00
virtual FTopLevelAssetPath FindAssetPath ( const FAssetKey & InKey ) const override ;
virtual TArray < FTopLevelAssetPath > FindAssetPaths ( const FAssetKey & InKey ) const override ;
2024-05-08 14:53:53 -04:00
virtual FMetasoundAssetBase * GetAsAsset ( UObject & InObject ) const override ;
virtual const FMetasoundAssetBase * GetAsAsset ( const UObject & InObject ) const override ;
# if WITH_EDITOR
virtual TSet < FAssetInfo > GetReferencedAssetClasses ( const FMetasoundAssetBase & InAssetBase ) const override ;
2024-09-10 10:26:02 -04:00
virtual bool ReassignClassName ( TScriptInterface < IMetaSoundDocumentInterface > DocInterface ) override ;
2024-05-08 14:53:53 -04:00
# endif // WITH_EDITOR
2024-08-23 21:59:54 -04:00
virtual void IterateAssets ( TFunctionRef < void ( const FAssetKey , const TArray < FTopLevelAssetPath > & ) > Iter ) const override ;
virtual void ReloadMetaSoundAssets ( ) const override ;
2024-05-08 14:53:53 -04:00
virtual void RemoveAsset ( const UObject & InObject ) override ;
virtual void RemoveAsset ( const FAssetData & InAssetData ) override ;
2024-05-10 12:40:21 -04:00
virtual void RenameAsset ( const FAssetData & InAssetData , const FString & InOldObjectPath ) override ;
2024-07-17 17:00:42 -04:00
virtual void SetLogActiveAssetsOnShutdown ( bool bInLogActiveAssetsOnShutdown ) override ;
2024-05-08 14:53:53 -04:00
virtual FMetasoundAssetBase * TryLoadAssetFromKey ( const FAssetKey & InKey ) const override ;
virtual bool TryGetAssetIDFromClassName ( const FMetasoundFrontendClassName & InClassName , FGuid & OutGuid ) const override ;
virtual bool TryLoadReferencedAssets ( const FMetasoundAssetBase & InAssetBase , TArray < FMetasoundAssetBase * > & OutReferencedAssets ) const override ;
virtual void WaitUntilAsyncLoadReferencedAssetsComplete ( FMetasoundAssetBase & InAssetBase ) override ;
/* FGCObject */
virtual void AddReferencedObjects ( FReferenceCollector & Collector ) override ;
virtual FString GetReferencerName ( ) const override { return TEXT ( " FMetaSoundAssetManager " ) ; }
private :
TArray < FMetaSoundAsyncAssetDependencies > LoadingDependencies ;
FMetaSoundAsyncAssetDependencies * FindLoadingDependencies ( const UObject * InParentAsset ) ;
FMetaSoundAsyncAssetDependencies * FindLoadingDependencies ( int32 InLoadID ) ;
void RemoveLoadingDependencies ( int32 InLoadID ) ;
void OnAssetsLoaded ( int32 InLoadID ) ;
FStreamableManager StreamableManager ;
int32 AsyncLoadIDCounter = 0 ;
int32 AutoUpdateDenyListChangeID = INDEX_NONE ;
TSet < FName > AutoUpdateDenyListCache ;
std : : atomic < bool > bIsInitialAssetScanComplete = false ;
2024-05-10 12:40:21 -04:00
TMap < FAssetKey , TArray < FTopLevelAssetPath > > PathMap ;
2024-07-17 17:00:42 -04:00
2024-09-10 10:26:02 -04:00
// Critical section primarily for allowing safe access of path map during async loading of MetaSound assets.
mutable FCriticalSection PathMapCriticalSection ;
2024-07-17 17:00:42 -04:00
bool bLogActiveAssetsOnShutdown = true ;
2024-05-08 14:53:53 -04:00
} ;
FMetaSoundAssetManager : : ~ FMetaSoundAssetManager ( )
{
2024-05-14 20:20:01 -04:00
# if !NO_LOGGING
2024-09-10 10:26:02 -04:00
if ( bLogActiveAssetsOnShutdown )
2024-05-08 14:53:53 -04:00
{
2024-09-10 10:26:02 -04:00
TMap < FAssetKey , TArray < FTopLevelAssetPath > > PathsOnShutdown ;
2024-05-14 20:20:01 -04:00
{
2024-09-10 10:26:02 -04:00
FScopeLock Lock ( & PathMapCriticalSection ) ;
PathsOnShutdown = MoveTemp ( PathMap ) ;
PathMap . Reset ( ) ;
}
if ( ! PathsOnShutdown . IsEmpty ( ) )
{
UE_LOG ( LogMetaSound , Display , TEXT ( " AssetManager is shutting down with the following %i assets active: " ) , PathsOnShutdown . Num ( ) ) ;
for ( const TPair < FAssetKey , TArray < FTopLevelAssetPath > > & Pair : PathsOnShutdown )
2024-05-14 20:20:01 -04:00
{
2024-09-10 10:26:02 -04:00
for ( const FTopLevelAssetPath & Path : Pair . Value )
2024-05-14 20:20:01 -04:00
{
2024-09-10 10:26:02 -04:00
UE_LOG ( LogMetaSound , Display , TEXT ( " - %s " ) , * Path . ToString ( ) ) ;
2024-05-14 20:20:01 -04:00
}
}
}
2024-05-08 14:53:53 -04:00
}
2024-05-14 20:20:01 -04:00
# endif // !NO_LOGGING
2024-05-08 14:53:53 -04:00
}
void FMetaSoundAssetManager : : AddReferencedObjects ( FReferenceCollector & Collector )
{
for ( FMetaSoundAsyncAssetDependencies & Dependencies : LoadingDependencies )
{
Collector . AddReferencedObject ( Dependencies . MetaSound ) ;
}
}
# if WITH_EDITORONLY_DATA
2024-05-29 15:33:29 -04:00
bool FMetaSoundAssetManager : : AddAssetReferences ( FMetasoundAssetBase & InAssetBase )
2024-05-08 14:53:53 -04:00
{
using namespace Frontend ;
{
const FMetasoundFrontendDocument & Document = InAssetBase . GetConstDocumentChecked ( ) ;
const FAssetKey AssetKey ( Document . RootGraph . Metadata ) ;
if ( ! ContainsKey ( AssetKey ) )
{
AddOrUpdateAsset ( * InAssetBase . GetOwningAsset ( ) ) ;
UE_LOG ( LogMetaSound , Verbose , TEXT ( " Adding asset '%s' to MetaSoundAsset registry. " ) , * InAssetBase . GetOwningAssetName ( ) ) ;
}
}
bool bAddFromReferencedAssets = false ;
const TSet < FString > & ReferencedAssetClassKeys = InAssetBase . GetReferencedAssetClassKeys ( ) ;
for ( const FString & KeyString : ReferencedAssetClassKeys )
{
FNodeRegistryKey RegistryKey ;
const bool bIsKey = FNodeRegistryKey : : Parse ( KeyString , RegistryKey ) ;
if ( ! bIsKey | | ! ContainsKey ( RegistryKey ) )
{
UE_LOG ( LogMetaSound , Verbose , TEXT ( " Missing referenced class '%s' asset entry. " ) , * KeyString ) ;
bAddFromReferencedAssets = true ;
}
}
// All keys are loaded
if ( ! bAddFromReferencedAssets )
{
2024-05-29 15:33:29 -04:00
return false ;
2024-05-08 14:53:53 -04:00
}
UE_LOG ( LogMetaSound , Verbose , TEXT ( " Attempting preemptive reference load... " ) ) ;
TArray < FMetasoundAssetBase * > ReferencedAssets = InAssetBase . GetReferencedAssets ( ) ;
for ( FMetasoundAssetBase * Asset : ReferencedAssets )
{
if ( Asset )
{
const FMetasoundFrontendDocument & RefDocument = Asset - > GetConstDocumentChecked ( ) ;
2024-05-29 15:33:29 -04:00
const FAssetKey ClassKey = FAssetKey ( RefDocument . RootGraph ) ;
2024-05-08 14:53:53 -04:00
if ( ! ContainsKey ( ClassKey ) )
{
UE_LOG ( LogMetaSound , Verbose ,
TEXT ( " Preemptive load of class '%s' due to early "
" registration request (asset scan likely not complete). " ) ,
* ClassKey . ToString ( ) ) ;
UObject * MetaSoundObject = Asset - > GetOwningAsset ( ) ;
if ( ensureAlways ( MetaSoundObject ) )
{
AddOrUpdateAsset ( * MetaSoundObject ) ;
}
}
}
else
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Null referenced dependent asset in %s. Resaving asset in editor may fix the issue " ) , * InAssetBase . GetOwningAssetName ( ) ) ;
}
}
2024-05-29 15:33:29 -04:00
return true ;
2024-05-08 14:53:53 -04:00
}
# endif // WITH_EDITORONLY_DATA
Frontend : : FAssetKey FMetaSoundAssetManager : : AddOrUpdateAsset ( const UObject & InObject )
{
using namespace AssetSubsystemPrivate ;
using namespace Frontend ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( FMetaSoundAssetManager : : AddOrUpdateAsset_UObject ) ;
const FMetasoundAssetBase * MetaSoundAsset = Metasound : : IMetasoundUObjectRegistry : : Get ( ) . GetObjectAsAssetBase ( & InObject ) ;
check ( MetaSoundAsset ) ;
const FMetasoundFrontendDocument & Document = MetaSoundAsset - > GetConstDocumentChecked ( ) ;
const FAssetKey AssetKey = FAssetKey ( Document . RootGraph ) ;
if ( AssetKey . IsValid ( ) )
{
2024-09-10 10:26:02 -04:00
AssetSubsystemPrivate : : AddPath ( & PathMapCriticalSection , PathMap , AssetKey , FTopLevelAssetPath ( & InObject ) ) ;
2024-05-08 14:53:53 -04:00
}
return AssetKey ;
}
Frontend : : FAssetKey FMetaSoundAssetManager : : AddOrUpdateAsset ( const FAssetData & InAssetData )
{
using namespace Frontend ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( UMetaSoundAssetSubsystem : : AddOrUpdateAsset_AssetData ) ;
2024-10-01 19:50:09 -04:00
// Invalid ClassID means the node could not be registered.
// Let caller report or ensure as necessary.
FAssetKey AssetKey = FAssetKey : : GetInvalid ( ) ;
// Don't add temporary assets used for diffing
if ( InAssetData . HasAnyPackageFlags ( PKG_ForDiffing ) )
{
return AssetKey ;
}
2024-05-08 14:53:53 -04:00
FNodeClassInfo ClassInfo ;
bool bClassInfoFound = AssetSubsystemPrivate : : GetAssetClassInfo ( InAssetData , ClassInfo ) ;
if ( ! bClassInfoFound )
{
UObject * Object = nullptr ;
FSoftObjectPath Path = InAssetData . ToSoftObjectPath ( ) ;
if ( ! FPackageName : : GetPackageMountPoint ( InAssetData . GetObjectPathString ( ) ) . IsNone ( ) )
{
if ( InAssetData . IsAssetLoaded ( ) )
{
Object = Path . ResolveObject ( ) ;
UE_LOG ( LogMetaSound , Verbose , TEXT ( " Adding loaded asset '%s' to MetaSoundAsset registry. " ) , * Object - > GetName ( ) ) ;
2023-01-10 15:23:40 -05:00
}
else
{
2024-05-08 14:53:53 -04:00
Object = Path . TryLoad ( ) ;
UE_LOG ( LogMetaSound , Verbose , TEXT ( " Loaded asset '%s' and adding to MetaSoundAsset registry. " ) , * Object - > GetName ( ) ) ;
2023-01-10 15:23:40 -05:00
}
}
2024-05-08 14:53:53 -04:00
if ( Object )
{
return AddOrUpdateAsset ( * Object ) ;
}
}
if ( ClassInfo . AssetClassID . IsValid ( ) )
{
2024-10-01 19:50:09 -04:00
AssetKey = FAssetKey ( ClassInfo . ClassName , ClassInfo . Version ) ;
2024-05-10 12:40:21 -04:00
if ( AssetKey . IsValid ( ) )
2024-05-08 14:53:53 -04:00
{
2024-09-10 10:26:02 -04:00
AssetSubsystemPrivate : : AddPath ( & PathMapCriticalSection , PathMap , AssetKey , ClassInfo . AssetPath ) ;
2024-05-08 14:53:53 -04:00
}
}
2024-10-01 19:50:09 -04:00
return AssetKey ;
2024-05-08 14:53:53 -04:00
}
bool FMetaSoundAssetManager : : CanAutoUpdate ( const FMetasoundFrontendClassName & InClassName ) const
{
const UMetaSoundSettings * Settings = GetDefault < UMetaSoundSettings > ( ) ;
if ( ! Settings - > bAutoUpdateEnabled )
{
2023-01-10 15:23:40 -05:00
return false ;
}
2024-05-08 14:53:53 -04:00
return ! AutoUpdateDenyListCache . Contains ( InClassName . GetFullName ( ) ) ;
2021-11-07 23:43:01 -05:00
}
2024-05-08 14:53:53 -04:00
bool FMetaSoundAssetManager : : ContainsKey ( const Metasound : : Frontend : : FAssetKey & InKey ) const
{
2024-09-10 10:26:02 -04:00
FScopeLock Lock ( & PathMapCriticalSection ) ;
2024-05-08 14:53:53 -04:00
return PathMap . Contains ( InKey ) ;
}
FMetaSoundAsyncAssetDependencies * FMetaSoundAssetManager : : FindLoadingDependencies ( const UObject * InParentAsset )
{
auto IsEqualMetaSoundUObject = [ InParentAsset ] ( const FMetaSoundAsyncAssetDependencies & InDependencies ) - > bool
{
return ( InDependencies . MetaSound = = InParentAsset ) ;
} ;
return LoadingDependencies . FindByPredicate ( IsEqualMetaSoundUObject ) ;
}
FMetaSoundAsyncAssetDependencies * FMetaSoundAssetManager : : FindLoadingDependencies ( int32 InLoadID )
{
auto IsEqualID = [ InLoadID ] ( const FMetaSoundAsyncAssetDependencies & InDependencies ) - > bool
{
return ( InDependencies . LoadID = = InLoadID ) ;
} ;
return LoadingDependencies . FindByPredicate ( IsEqualID ) ;
}
FMetasoundAssetBase * FMetaSoundAssetManager : : FindAsset ( const Metasound : : Frontend : : FAssetKey & InKey ) const
{
2024-09-10 10:26:02 -04:00
FTopLevelAssetPath AssetPath = FindAssetPath ( InKey ) ;
if ( AssetPath . IsValid ( ) )
2024-05-08 14:53:53 -04:00
{
2024-09-10 10:26:02 -04:00
if ( UObject * Object = FSoftObjectPath ( AssetPath , { } ) . ResolveObject ( ) )
2024-05-08 14:53:53 -04:00
{
return GetAsAsset ( * Object ) ;
}
}
return nullptr ;
}
TScriptInterface < IMetaSoundDocumentInterface > FMetaSoundAssetManager : : FindAssetAsDocumentInterface ( const Metasound : : Frontend : : FAssetKey & InKey ) const
{
2024-09-10 10:26:02 -04:00
const FTopLevelAssetPath AssetPath = FindAssetPath ( InKey ) ;
if ( AssetPath . IsValid ( ) )
2024-05-08 14:53:53 -04:00
{
2024-09-10 10:26:02 -04:00
if ( UObject * Object = FSoftObjectPath ( AssetPath , { } ) . ResolveObject ( ) )
2024-05-08 14:53:53 -04:00
{
return TScriptInterface < IMetaSoundDocumentInterface > ( Object ) ;
}
}
return nullptr ;
}
2024-09-10 10:26:02 -04:00
FTopLevelAssetPath FMetaSoundAssetManager : : FindAssetPath ( const Metasound : : Frontend : : FAssetKey & InKey ) const
2024-05-08 14:53:53 -04:00
{
2024-09-10 10:26:02 -04:00
FScopeLock Lock ( & PathMapCriticalSection ) ;
2024-05-10 12:40:21 -04:00
if ( const TArray < FTopLevelAssetPath > * Paths = PathMap . Find ( InKey ) )
{
if ( ! Paths - > IsEmpty ( ) )
{
2024-09-10 10:26:02 -04:00
return Paths - > Last ( ) ;
2024-05-10 12:40:21 -04:00
}
}
return nullptr ;
2024-05-08 14:53:53 -04:00
}
2024-09-10 10:26:02 -04:00
TArray < FTopLevelAssetPath > FMetaSoundAssetManager : : FindAssetPaths ( const Metasound : : Frontend : : FAssetKey & InKey ) const
2024-06-20 16:42:12 -04:00
{
2024-09-10 10:26:02 -04:00
FScopeLock Lock ( & PathMapCriticalSection ) ;
2024-06-20 16:42:12 -04:00
if ( const TArray < FTopLevelAssetPath > * Paths = PathMap . Find ( InKey ) )
{
2024-09-10 10:26:02 -04:00
return * Paths ;
2024-06-20 16:42:12 -04:00
}
return { } ;
}
2024-05-08 14:53:53 -04:00
FMetasoundAssetBase * FMetaSoundAssetManager : : GetAsAsset ( UObject & InObject ) const
{
return IMetasoundUObjectRegistry : : Get ( ) . GetObjectAsAssetBase ( & InObject ) ;
}
const FMetasoundAssetBase * FMetaSoundAssetManager : : GetAsAsset ( const UObject & InObject ) const
{
return IMetasoundUObjectRegistry : : Get ( ) . GetObjectAsAssetBase ( & InObject ) ;
}
void FMetaSoundAssetManager : : 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 ) ;
}
}
void FMetaSoundAssetManager : : OnAssetScanComplete ( )
{
bIsInitialAssetScanComplete = true ;
}
# if WITH_EDITOR
TSet < UMetaSoundAssetSubsystem : : FAssetInfo > FMetaSoundAssetManager : : GetReferencedAssetClasses ( const FMetasoundAssetBase & InAssetBase ) const
{
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( FMetaSoundAssetManager : : GetReferencedAssetClasses ) ;
using namespace Metasound : : Frontend ;
TSet < FAssetInfo > OutAssetInfos ;
const FMetasoundFrontendDocument & Document = InAssetBase . GetConstDocumentChecked ( ) ;
for ( const FMetasoundFrontendClass & Class : Document . Dependencies )
{
if ( Class . Metadata . GetType ( ) ! = EMetasoundFrontendClassType : : External )
{
continue ;
}
2024-05-08 14:58:22 -04:00
const FAssetKey AssetKey ( Class . Metadata ) ;
2024-09-10 10:26:02 -04:00
FTopLevelAssetPath ObjectPath = FindAssetPath ( AssetKey ) ;
if ( ObjectPath . IsValid ( ) )
2024-05-08 14:53:53 -04:00
{
2024-09-10 10:26:02 -04:00
FAssetInfo AssetInfo { FNodeRegistryKey ( Class . Metadata ) , FSoftObjectPath ( ObjectPath ) } ;
2024-05-08 14:58:22 -04:00
OutAssetInfos . Add ( MoveTemp ( AssetInfo ) ) ;
2024-05-08 14:53:53 -04:00
}
else
{
2024-05-08 14:58:22 -04:00
FNodeRegistryKey RegistryKey ( Class . Metadata ) ;
2024-05-08 14:53:53 -04:00
const FMetasoundFrontendRegistryContainer * Registry = FMetasoundFrontendRegistryContainer : : Get ( ) ;
check ( Registry ) ;
2024-05-08 14:58:22 -04:00
const bool bIsRegistered = Registry - > IsNodeRegistered ( RegistryKey ) ;
2024-05-08 14:53:53 -04:00
bool bReportFail = false ;
if ( bIsRegistered )
{
2024-05-08 14:58:22 -04:00
if ( ! Registry - > IsNodeNative ( RegistryKey ) )
2024-05-08 14:53:53 -04:00
{
bReportFail = true ;
}
}
else
{
// Don't report failure if a matching class with a matching major version and higher minor version exists (it will be autoupdated)
FMetasoundFrontendClass FrontendClass ;
2024-05-08 14:58:22 -04:00
const bool bDidFindClassWithName = ISearchEngine : : Get ( ) . FindClassWithHighestVersion ( AssetKey . ClassName . ToNodeClassName ( ) , FrontendClass ) ;
2024-05-08 14:53:53 -04:00
if ( ! ( bDidFindClassWithName & &
2024-05-08 14:58:22 -04:00
AssetKey . Version . Major = = FrontendClass . Metadata . GetVersion ( ) . Major & &
AssetKey . Version . Minor < FrontendClass . Metadata . GetVersion ( ) . Minor ) )
2024-05-08 14:53:53 -04:00
{
bReportFail = true ;
}
}
if ( bReportFail )
{
if ( bIsInitialAssetScanComplete )
{
2024-05-08 14:58:22 -04:00
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. " ) , * AssetKey . ToString ( ) , * InAssetBase . GetOwningAssetName ( ) ) ;
2024-05-08 14:53:53 -04:00
}
else
{
2024-05-08 14:58:22 -04:00
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 " ) , * AssetKey . ToString ( ) , * InAssetBase . GetOwningAssetName ( ) ) ;
2024-05-08 14:53:53 -04:00
}
}
}
}
return MoveTemp ( OutAssetInfos ) ;
}
2024-09-10 10:26:02 -04:00
bool FMetaSoundAssetManager : : ReassignClassName ( TScriptInterface < IMetaSoundDocumentInterface > DocInterface )
{
# if WITH_EDITORONLY_DATA
UObject * MetaSoundObject = DocInterface . GetObject ( ) ;
if ( ! MetaSoundObject )
{
return false ;
}
FMetasoundAssetBase * AssetBase = GetAsAsset ( * MetaSoundObject ) ;
if ( ! AssetBase )
{
return false ;
}
FMetaSoundFrontendDocumentBuilder & Builder = FDocumentBuilderRegistry : : GetChecked ( ) . FindOrBeginBuilding ( DocInterface ) ;
const FMetasoundFrontendClassMetadata & ClassMetadata = Builder . GetConstDocumentChecked ( ) . RootGraph . Metadata ;
const FTopLevelAssetPath Path ( MetaSoundObject ) ;
AssetBase - > UnregisterGraphWithFrontend ( ) ;
{
const FAssetKey OldAssetKey ( ClassMetadata . GetClassName ( ) , ClassMetadata . GetVersion ( ) ) ;
AssetSubsystemPrivate : : RemovePath ( & PathMapCriticalSection , PathMap , OldAssetKey , Path ) ;
}
Builder . GenerateNewClassName ( ) ;
{
const FAssetKey NewAssetKey ( ClassMetadata . GetClassName ( ) , ClassMetadata . GetVersion ( ) ) ;
AssetSubsystemPrivate : : AddPath ( & PathMapCriticalSection , PathMap , NewAssetKey , Path ) ;
}
AssetBase - > UpdateAndRegisterForExecution ( ) ;
return true ;
# else // !WITH_EDITORONLY_DATA
return false ;
# endif // !WITH_EDITORONLY_DATA
}
2024-05-08 14:53:53 -04:00
# endif // WITH_EDITOR
2024-08-23 21:59:54 -04:00
void FMetaSoundAssetManager : : IterateAssets ( TFunctionRef < void ( const FAssetKey , const TArray < FTopLevelAssetPath > & ) > Iter ) const
{
for ( const TPair < FAssetKey , TArray < FTopLevelAssetPath > > & Pair : PathMap )
{
Iter ( Pair . Key , Pair . Value ) ;
}
}
2024-05-08 14:53:53 -04:00
void FMetaSoundAssetManager : : RebuildDenyListCache ( const UAssetManager & InAssetManager )
{
using namespace Metasound : : Frontend ;
const UMetaSoundSettings * Settings = GetDefault < UMetaSoundSettings > ( ) ;
if ( Settings - > DenyListCacheChangeID = = AutoUpdateDenyListChangeID )
{
return ;
}
AutoUpdateDenyListCache . Reset ( ) ;
for ( const FMetasoundFrontendClassName & ClassName : Settings - > AutoUpdateDenylist )
{
AutoUpdateDenyListCache . Add ( ClassName . GetFullName ( ) ) ;
}
check ( UAssetManager : : IsInitialized ( ) ) ;
UAssetManager & AssetManager = UAssetManager : : Get ( ) ;
for ( const FDefaultMetaSoundAssetAutoUpdateSettings & UpdateSettings : Settings - > AutoUpdateAssetDenylist )
{
FAssetData AssetData ;
if ( AssetManager . GetAssetDataForPath ( UpdateSettings . MetaSound , AssetData ) )
{
FString AssetClassID ;
if ( AssetData . GetTagValue ( AssetTags : : AssetClassID , AssetClassID ) )
{
const FMetasoundFrontendClassName ClassName = { FName ( ) , * AssetClassID , FName ( ) } ;
AutoUpdateDenyListCache . Add ( ClassName . GetFullName ( ) ) ;
}
}
}
AutoUpdateDenyListChangeID = Settings - > DenyListCacheChangeID ;
}
void FMetaSoundAssetManager : : RegisterAssetClassesInDirectories ( const TArray < FMetaSoundAssetDirectory > & InDirectories )
{
TArray < FDirectoryPath > Directories ;
Algo : : Transform ( InDirectories , Directories , [ ] ( const FMetaSoundAssetDirectory & AssetDir ) { return AssetDir . Directory ; } ) ;
SearchAndIterateDirectoryAssets ( Directories , [ this ] ( const FAssetData & AssetData )
{
AddOrUpdateAsset ( AssetData ) ;
FMetasoundAssetBase * MetaSoundAsset = Metasound : : IMetasoundUObjectRegistry : : Get ( ) . GetObjectAsAssetBase ( AssetData . GetAsset ( ) ) ;
check ( MetaSoundAsset ) ;
Metasound : : Frontend : : FMetaSoundAssetRegistrationOptions RegOptions ;
if ( const UMetaSoundSettings * Settings = GetDefault < UMetaSoundSettings > ( ) )
{
RegOptions . bAutoUpdateLogWarningOnDroppedConnection = Settings - > bAutoUpdateLogWarningOnDroppedConnection ;
}
2024-06-17 12:51:18 -04:00
MetaSoundAsset - > UpdateAndRegisterForExecution ( RegOptions ) ;
2024-05-08 14:53:53 -04:00
} ) ;
}
void FMetaSoundAssetManager : : RemoveAsset ( const UObject & InObject )
{
using namespace Frontend ;
2024-05-14 20:20:01 -04:00
TScriptInterface < const IMetaSoundDocumentInterface > DocInterface ( & InObject ) ;
check ( DocInterface . GetObject ( ) ) ;
const FMetasoundFrontendDocument & Document = DocInterface - > GetConstDocument ( ) ;
const FMetasoundFrontendClassMetadata & Metadata = Document . RootGraph . Metadata ;
2024-06-05 11:00:21 -04:00
const FTopLevelAssetPath AssetPath ( & InObject ) ;
2024-05-14 20:20:01 -04:00
if ( IDocumentBuilderRegistry * BuilderRegistry = IDocumentBuilderRegistry : : Get ( ) )
2024-05-08 14:53:53 -04:00
{
2024-05-14 20:20:01 -04:00
constexpr bool bForceUnregister = true ;
2024-06-05 11:00:21 -04:00
BuilderRegistry - > FinishBuilding ( Metadata . GetClassName ( ) , AssetPath , bForceUnregister ) ;
2024-05-08 14:53:53 -04:00
}
2024-05-14 20:20:01 -04:00
const FAssetKey AssetKey ( Metadata . GetClassName ( ) , Metadata . GetVersion ( ) ) ;
2024-09-10 10:26:02 -04:00
AssetSubsystemPrivate : : RemovePath ( & PathMapCriticalSection , PathMap , AssetKey , AssetPath ) ;
2024-05-08 14:53:53 -04:00
}
void FMetaSoundAssetManager : : RemoveAsset ( const FAssetData & InAssetData )
{
using namespace Frontend ;
FNodeClassInfo ClassInfo ;
2024-06-05 11:00:21 -04:00
const FTopLevelAssetPath AssetPath ( InAssetData . PackageName , InAssetData . AssetName ) ;
2024-05-08 14:53:53 -04:00
if ( ensureAlways ( AssetSubsystemPrivate : : GetAssetClassInfo ( InAssetData , ClassInfo ) ) )
{
if ( IDocumentBuilderRegistry * BuilderRegistry = IDocumentBuilderRegistry : : Get ( ) )
{
2024-05-10 12:40:21 -04:00
constexpr bool bForceUnregister = true ;
2024-06-05 11:00:21 -04:00
BuilderRegistry - > FinishBuilding ( ClassInfo . ClassName , AssetPath , bForceUnregister ) ;
2024-05-08 14:53:53 -04:00
}
const FAssetKey AssetKey ( ClassInfo . ClassName , ClassInfo . Version ) ;
2024-09-10 10:26:02 -04:00
AssetSubsystemPrivate : : RemovePath ( & PathMapCriticalSection , PathMap , AssetKey , AssetPath ) ;
2024-05-08 14:53:53 -04:00
}
}
void FMetaSoundAssetManager : : RemoveLoadingDependencies ( int32 InLoadID )
{
auto IsEqualID = [ InLoadID ] ( const FMetaSoundAsyncAssetDependencies & InDependencies ) - > bool
{
return ( InDependencies . LoadID = = InLoadID ) ;
} ;
LoadingDependencies . RemoveAllSwap ( IsEqualID ) ;
}
2024-05-10 12:40:21 -04:00
void FMetaSoundAssetManager : : RenameAsset ( const FAssetData & InAssetData , const FString & InOldObjectPath )
2024-05-08 14:53:53 -04:00
{
using namespace Frontend ;
FMetasoundAssetBase * MetaSoundAsset = GetAsAsset ( * InAssetData . GetAsset ( ) ) ;
check ( MetaSoundAsset ) ;
FNodeClassInfo ClassInfo ;
if ( ensureAlways ( AssetSubsystemPrivate : : GetAssetClassInfo ( InAssetData , ClassInfo ) ) )
{
const FAssetKey AssetKey ( ClassInfo . ClassName , ClassInfo . Version ) ;
2024-05-10 12:40:21 -04:00
const FTopLevelAssetPath OldPath ( InOldObjectPath ) ;
2024-09-10 10:26:02 -04:00
AssetSubsystemPrivate : : RemovePath ( & PathMapCriticalSection , PathMap , AssetKey , OldPath ) ;
2024-05-08 14:53:53 -04:00
if ( ClassInfo . AssetClassID . IsValid ( ) )
{
2024-05-10 12:40:21 -04:00
if ( AssetKey . IsValid ( ) )
2024-05-08 14:53:53 -04:00
{
2024-09-10 10:26:02 -04:00
AssetSubsystemPrivate : : AddPath ( & PathMapCriticalSection , PathMap , AssetKey , ClassInfo . AssetPath ) ;
2024-05-08 14:53:53 -04:00
}
}
}
}
2024-09-10 10:26:02 -04:00
# if WITH_EDITOR
bool FMetaSoundAssetManager : : ReplaceReferencesInDirectory ( const TArray < FMetaSoundAssetDirectory > & InDirectories , const Metasound : : Frontend : : FNodeRegistryKey & OldClassKey , const Metasound : : Frontend : : FNodeRegistryKey & NewClassKey ) const
{
using namespace Frontend ;
bool bReferencesReplaced = false ;
# if WITH_EDITORONLY_DATA
if ( ! NewClassKey . IsValid ( ) )
{
return bReferencesReplaced ;
}
FMetasoundFrontendClass NewClass ;
const bool bNewClassExists = ISearchEngine : : Get ( ) . FindClassWithHighestVersion ( NewClassKey . ClassName , NewClass ) ;
if ( bNewClassExists )
{
TArray < FDirectoryPath > Directories ;
Algo : : Transform ( InDirectories , Directories , [ ] ( const FMetaSoundAssetDirectory & AssetDir ) { return AssetDir . Directory ; } ) ;
TMap < FNodeRegistryKey , FNodeRegistryKey > OldToNewReferenceKeys = { { OldClassKey , NewClassKey } } ;
SearchAndIterateDirectoryAssets ( Directories , [ this , & bReferencesReplaced , & OldToNewReferenceKeys ] ( const FAssetData & AssetData )
{
if ( UObject * MetaSoundObject = AssetData . GetAsset ( ) )
{
MetaSoundObject - > Modify ( ) ;
FMetaSoundFrontendDocumentBuilder & Builder = FDocumentBuilderRegistry : : GetChecked ( ) . FindOrBeginBuilding ( MetaSoundObject ) ;
const bool bDependencyUpdated = Builder . UpdateDependencyRegistryData ( OldToNewReferenceKeys ) ;
if ( bDependencyUpdated )
{
bReferencesReplaced = true ;
Builder . RemoveUnusedDependencies ( ) ;
if ( FMetasoundAssetBase * AssetBase = GetAsAsset ( * MetaSoundObject ) ; ensure ( AssetBase ) )
{
AssetBase - > RebuildReferencedAssetClasses ( ) ;
}
}
}
} ) ;
}
else
{
UE_LOG ( LogMetaSound , Display , TEXT ( " Cannot replace references in MetaSound assets found in given directory/directories: NewClass '%s' does not exist " ) , * NewClassKey . ToString ( ) ) ;
}
# endif // WITH_EDITORONLY_DATA
return bReferencesReplaced ;
}
# endif // WITH_EDITOR
2024-05-08 14:53:53 -04:00
void FMetaSoundAssetManager : : 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 ( ) ) ;
}
}
}
2024-08-23 21:59:54 -04:00
void FMetaSoundAssetManager : : ReloadMetaSoundAssets ( ) const
{
TSet < FMetasoundAssetBase * > ToReregister ;
IterateAssets ( [ & ToReregister ] ( const FAssetKey & AssetKey , const TArray < FTopLevelAssetPath > & Paths )
{
if ( FMetasoundAssetBase * Asset = IMetaSoundAssetManager : : GetChecked ( ) . FindAsset ( AssetKey ) )
{
if ( Asset - > IsRegistered ( ) )
{
ToReregister . Add ( Asset ) ;
Asset - > UnregisterGraphWithFrontend ( ) ;
}
}
} ) ;
// Handled in second loop to avoid re-registering referenced graphs more than once
IterateAssets ( [ & ToReregister ] ( const FAssetKey & AssetKey , const TArray < FTopLevelAssetPath > & Paths )
{
if ( FMetasoundAssetBase * Asset = IMetaSoundAssetManager : : GetChecked ( ) . FindAsset ( AssetKey ) )
{
if ( ToReregister . Contains ( Asset ) )
{
Asset - > UpdateAndRegisterForExecution ( ) ;
}
}
} ) ;
}
2024-09-10 10:26:02 -04:00
void FMetaSoundAssetManager : : SearchAndIterateDirectoryAssets ( const TArray < FDirectoryPath > & InDirectories , TFunctionRef < void ( const FAssetData & ) > InFunction ) const
2024-05-08 14:53:53 -04:00
{
if ( InDirectories . IsEmpty ( ) )
{
return ;
}
UAssetManager & AssetManager = UAssetManager : : Get ( ) ;
FAssetManagerSearchRules Rules ;
for ( const FDirectoryPath & Path : InDirectories )
{
Rules . AssetScanPaths . Add ( * Path . Path ) ;
}
Metasound : : IMetasoundUObjectRegistry : : Get ( ) . IterateRegisteredUClasses ( [ & ] ( UClass & RegisteredClass )
{
Rules . AssetBaseClass = & RegisteredClass ;
TArray < FAssetData > MetaSoundAssets ;
AssetManager . SearchAssetRegistryPaths ( MetaSoundAssets , Rules ) ;
for ( const FAssetData & AssetData : MetaSoundAssets )
{
InFunction ( AssetData ) ;
}
} ) ;
}
2024-07-17 17:00:42 -04:00
void FMetaSoundAssetManager : : SetLogActiveAssetsOnShutdown ( bool bInLogActiveAssetsOnShutdown )
{
bLogActiveAssetsOnShutdown = bInLogActiveAssetsOnShutdown ;
}
2024-05-08 14:53:53 -04:00
2024-05-10 12:40:21 -04:00
FMetasoundAssetBase * FMetaSoundAssetManager : : TryLoadAssetFromKey ( const Metasound : : Frontend : : FAssetKey & InAssetKey ) const
2024-05-08 14:53:53 -04:00
{
2024-09-10 10:26:02 -04:00
FTopLevelAssetPath ObjectPath = FindAssetPath ( InAssetKey ) ;
if ( ObjectPath . IsValid ( ) )
2024-05-08 14:53:53 -04:00
{
2024-09-10 10:26:02 -04:00
const FSoftObjectPath SoftPath ( ObjectPath ) ;
2024-05-08 14:53:53 -04:00
return TryLoadAsset ( SoftPath ) ;
}
return nullptr ;
}
bool FMetaSoundAssetManager : : TryGetAssetIDFromClassName ( const FMetasoundFrontendClassName & InClassName , FGuid & OutGuid ) const
{
return FGuid : : Parse ( InClassName . Name . ToString ( ) , OutGuid ) ;
}
FMetasoundAssetBase * FMetaSoundAssetManager : : TryLoadAsset ( const FSoftObjectPath & InObjectPath ) const
{
return Metasound : : IMetasoundUObjectRegistry : : Get ( ) . GetObjectAsAssetBase ( InObjectPath . TryLoad ( ) ) ;
}
bool FMetaSoundAssetManager : : 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 FString & KeyString : AssetClassKeys )
{
FNodeRegistryKey Key ;
FNodeRegistryKey : : Parse ( KeyString , Key ) ;
if ( FMetasoundAssetBase * MetaSound = TryLoadAssetFromKey ( Key ) )
{
OutReferencedAssets . Add ( MetaSound ) ;
}
else
{
UE_LOG ( LogMetaSound , Error , TEXT ( " Failed to find or load referenced MetaSound asset with key '%s' " ) , * KeyString ) ;
bSucceeded = false ;
}
}
return bSucceeded ;
}
void FMetaSoundAssetManager : : UnregisterAssetClassesInDirectories ( const TArray < FMetaSoundAssetDirectory > & InDirectories )
{
TArray < FDirectoryPath > Directories ;
Algo : : Transform ( InDirectories , Directories , [ ] ( const FMetaSoundAssetDirectory & AssetDir ) { return AssetDir . Directory ; } ) ;
SearchAndIterateDirectoryAssets ( Directories , [ this ] ( const FAssetData & AssetData )
{
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 = FNodeRegistryKey ( AssetClassInfo ) ;
const bool bIsRegistered = FMetasoundFrontendRegistryContainer : : Get ( ) - > IsNodeRegistered ( RegistryKey ) ;
if ( bIsRegistered )
{
FMetasoundFrontendRegistryContainer : : Get ( ) - > UnregisterNode ( RegistryKey ) ;
const FTopLevelAssetPath AssetPath ( AssetData . PackageName , AssetData . AssetName ) ;
const FAssetKey AssetKey ( AssetClassInfo . ClassName , AssetClassInfo . Version ) ;
2024-09-10 10:26:02 -04:00
AssetSubsystemPrivate : : RemovePath ( & PathMapCriticalSection , PathMap , AssetKey , AssetPath ) ;
2024-05-08 14:53:53 -04:00
}
}
}
} ) ;
}
void FMetaSoundAssetManager : : WaitUntilAsyncLoadReferencedAssetsComplete ( FMetasoundAssetBase & InAssetBase )
{
TSet < FMetasoundAssetBase * > TransitiveReferences ;
TArray < FMetasoundAssetBase * > TransitiveReferencesQueue ;
TransitiveReferences . Add ( & InAssetBase ) ;
TransitiveReferencesQueue . Add ( & InAssetBase ) ;
while ( ! TransitiveReferencesQueue . IsEmpty ( ) )
{
FMetasoundAssetBase * Reference = TransitiveReferencesQueue . Pop ( ) ;
UObject * OwningAsset = Reference - > GetOwningAsset ( ) ;
if ( ! OwningAsset )
{
continue ;
}
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 ( ) ;
}
}
for ( FMetasoundAssetBase * NextReference : Reference - > GetReferencedAssets ( ) )
{
bool bAlreadyInSet ;
TransitiveReferences . Add ( NextReference , & bAlreadyInSet ) ;
if ( ! bAlreadyInSet )
{
TransitiveReferencesQueue . Add ( NextReference ) ;
}
}
}
}
void DeinitializeAssetManager ( )
{
Frontend : : IMetaSoundAssetManager : : Deinitialize ( ) ;
}
void InitializeAssetManager ( )
{
Frontend : : IMetaSoundAssetManager : : Initialize ( MakeUnique < FMetaSoundAssetManager > ( ) ) ;
}
} // namespace Metasound::Engine
2021-11-07 23:43:01 -05:00
void UMetaSoundAssetSubsystem : : Initialize ( FSubsystemCollectionBase & InCollection )
{
2024-05-08 14:53:53 -04:00
FCoreDelegates : : OnPostEngineInit . AddUObject ( this , & UMetaSoundAssetSubsystem : : PostEngineInitInternal ) ;
2021-11-07 23:43:01 -05:00
}
2024-05-08 14:53:53 -04:00
void UMetaSoundAssetSubsystem : : PostEngineInitInternal ( )
2021-11-07 23:43:01 -05:00
{
2024-05-08 14:53:53 -04:00
using namespace Metasound : : Engine ;
2023-03-02 19:37:50 -05:00
check ( UAssetManager : : IsInitialized ( ) ) ;
UAssetManager & AssetManager = UAssetManager : : Get ( ) ;
2024-05-08 14:53:53 -04:00
AssetManager . CallOrRegister_OnCompletedInitialScan ( FSimpleMulticastDelegate : : FDelegate : : CreateUObject ( this , & UMetaSoundAssetSubsystem : : PostInitAssetScanInternal ) ) ;
FMetaSoundAssetManager : : GetChecked ( ) . RebuildDenyListCache ( AssetManager ) ;
2021-11-07 23:43:01 -05:00
}
2024-05-08 14:53:53 -04:00
void UMetaSoundAssetSubsystem : : PostInitAssetScanInternal ( )
2021-11-07 23:43:01 -05:00
{
2024-05-08 14:53:53 -04:00
using namespace Metasound : : Engine ;
METASOUND_TRACE_CPUPROFILER_EVENT_SCOPE ( UMetaSoundAssetSubsystem : : PostInitAssetScanInternal ) ;
2021-11-07 23:43:01 -05:00
2021-11-18 14:37:34 -05:00
const UMetaSoundSettings * Settings = GetDefault < UMetaSoundSettings > ( ) ;
if ( ensureAlways ( Settings ) )
2021-11-07 23:43:01 -05:00
{
2024-05-08 14:53:53 -04:00
FMetaSoundAssetManager & Manager = FMetaSoundAssetManager : : GetChecked ( ) ;
Manager . SearchAndIterateDirectoryAssets ( Settings - > DirectoriesToRegister , [ & Manager ] ( const FAssetData & AssetData )
2021-11-18 14:37:34 -05:00
{
2024-05-08 14:53:53 -04:00
Manager . AddOrUpdateAsset ( AssetData ) ;
2021-11-18 14:37:34 -05:00
} ) ;
2024-05-08 14:53:53 -04:00
Manager . OnAssetScanComplete ( ) ;
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 : : Frontend ;
2024-05-08 14:53:53 -04:00
IMetaSoundAssetManager : : GetChecked ( ) . AddAssetReferences ( InAssetBase ) ;
2021-11-07 23:43:01 -05:00
}
2024-05-08 14:53:53 -04:00
# endif // WITH_EDITORONLY_DATA
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 : : Frontend ;
2024-05-08 14:53:53 -04:00
return IMetaSoundAssetManager : : GetChecked ( ) . AddOrUpdateAsset ( InObject ) ;
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 : : Frontend ;
2024-05-08 14:53:53 -04:00
return IMetaSoundAssetManager : : GetChecked ( ) . AddOrUpdateAsset ( InAssetData ) ;
- Fix for attempting to access EngineSubsystem during MetaSound versioning (serialization), which can assert when apparently certain commands in certain contexts can attempt to preload assets prior to the init phase.
- Minor Fix for LocText duplication
#tests BuildCookRun, -game, version MetaSounds assets in editor, PIE
[FYI] bob.tellez
Original CL Desc
-----------------------------------------------------------------
[Backout] - CL33084850
[FYI] Rob.Gay
Original CL Desc
-----------------------------------------------------------------
Version Metasound Document to include all ed data and make all Metasound EdGraph data transient
- Add input template nodes
- Add comment node data to document
- Keep references to member literal data (i.e. knob/slider ranges) in document metadata to ensure continued serialization and flexibility to add more editor-only fields and literal metadata
- Misc builder API updates, bug fixes and migration of controllers to builder API in anticipation of pages
- Sunset non-deterministic guid cvar
#rb phil.popp, helen.yang
[FYI] sondra.moyls
#tests Standard Automated Audio Tests, EngineTests, Offline QA Smoke pass, CPR, etc., extensive MetaSound Editor use, -game MetaSound qa levels, AudioUnitTests
#jira UE-194159
[CL 33102023 by rob gay in ue5-main branch]
2024-04-19 10:09:04 -04:00
}
2021-11-07 23:43:01 -05:00
bool UMetaSoundAssetSubsystem : : CanAutoUpdate ( const FMetasoundFrontendClassName & InClassName ) const
{
2024-05-08 14:53:53 -04:00
using namespace Metasound : : Frontend ;
return IMetaSoundAssetManager : : GetChecked ( ) . CanAutoUpdate ( InClassName ) ;
2021-11-07 23:43:01 -05:00
}
bool UMetaSoundAssetSubsystem : : ContainsKey ( const Metasound : : Frontend : : FNodeRegistryKey & InRegistryKey ) const
{
2024-05-08 14:53:53 -04:00
using namespace Metasound : : Frontend ;
return IMetaSoundAssetManager : : GetChecked ( ) . ContainsKey ( FAssetKey ( InRegistryKey ) ) ;
2021-11-07 23:43:01 -05:00
}
2024-01-31 17:59:29 -05:00
FMetasoundAssetBase * UMetaSoundAssetSubsystem : : GetAsAsset ( UObject & InObject ) const
{
2024-05-08 14:53:53 -04:00
using namespace Metasound : : Frontend ;
return IMetaSoundAssetManager : : GetChecked ( ) . GetAsAsset ( InObject ) ;
2024-01-31 17:59:29 -05:00
}
const FMetasoundAssetBase * UMetaSoundAssetSubsystem : : GetAsAsset ( const UObject & InObject ) const
2021-11-07 23:43:01 -05:00
{
using namespace Metasound : : Frontend ;
2024-05-08 14:53:53 -04:00
return IMetaSoundAssetManager : : GetChecked ( ) . GetAsAsset ( InObject ) ;
2021-11-07 23:43:01 -05:00
}
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
{
using namespace Metasound : : Frontend ;
2024-05-08 14:53:53 -04:00
return IMetaSoundAssetManager : : GetChecked ( ) . GetReferencedAssetClasses ( InAssetBase ) ;
2021-11-07 23:43:01 -05:00
}
2024-01-31 17:59:29 -05:00
# endif // WITH_EDITOR
2021-11-07 23:43:01 -05:00
FMetasoundAssetBase * UMetaSoundAssetSubsystem : : TryLoadAssetFromKey ( const Metasound : : Frontend : : FNodeRegistryKey & RegistryKey ) const
{
2024-05-08 14:53:53 -04:00
using namespace Metasound : : Frontend ;
return IMetaSoundAssetManager : : GetChecked ( ) . TryLoadAssetFromKey ( RegistryKey ) ;
2021-11-07 23:43:01 -05:00
}
bool UMetaSoundAssetSubsystem : : TryLoadReferencedAssets ( const FMetasoundAssetBase & InAssetBase , TArray < FMetasoundAssetBase * > & OutReferencedAssets ) const
{
using namespace Metasound : : Frontend ;
2024-05-08 14:53:53 -04:00
return IMetaSoundAssetManager : : GetChecked ( ) . TryLoadReferencedAssets ( InAssetBase , OutReferencedAssets ) ;
2022-10-13 17:38:11 -04:00
}
2021-11-07 23:43:01 -05:00
const FSoftObjectPath * UMetaSoundAssetSubsystem : : FindObjectPathFromKey ( const Metasound : : Frontend : : FNodeRegistryKey & InRegistryKey ) const
{
2024-05-08 14:53:53 -04:00
using namespace Metasound : : Frontend ;
static FSoftObjectPath TempPath ;
TempPath . Reset ( ) ;
2024-09-10 10:26:02 -04:00
const FTopLevelAssetPath Path = IMetaSoundAssetManager : : GetChecked ( ) . FindAssetPath ( InRegistryKey ) ;
if ( Path . IsValid ( ) )
2024-05-08 14:53:53 -04:00
{
2024-09-10 10:26:02 -04:00
TempPath = FSoftObjectPath ( Path ) ;
2024-05-08 14:53:53 -04:00
}
return & TempPath ;
2021-11-07 23:43:01 -05:00
}
FMetasoundAssetBase * UMetaSoundAssetSubsystem : : TryLoadAsset ( const FSoftObjectPath & InObjectPath ) const
{
2024-05-08 14:53:53 -04:00
using namespace Metasound : : Frontend ;
return IMetaSoundAssetManager : : GetChecked ( ) . TryLoadAsset ( InObjectPath ) ;
2021-11-07 23:43:01 -05:00
}
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 : : Frontend ;
2024-05-08 14:53:53 -04:00
IMetaSoundAssetManager : : GetChecked ( ) . RemoveAsset ( InObject ) ;
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 : : Frontend ;
2024-05-08 14:53:53 -04:00
IMetaSoundAssetManager : : GetChecked ( ) . RemoveAsset ( InAssetData ) ;
2021-11-07 23:43:01 -05:00
}
2024-05-10 12:40:21 -04:00
void UMetaSoundAssetSubsystem : : RenameAsset ( const FAssetData & InAssetData , bool /* bInReregisterWithFrontend */ )
2021-11-07 23:43:01 -05:00
{
2024-05-08 14:53:53 -04:00
using namespace Metasound : : Frontend ;
2024-05-10 12:40:21 -04:00
IMetaSoundAssetManager : : GetChecked ( ) . RenameAsset ( InAssetData , { } ) ;
2021-11-07 23:43:01 -05:00
}
2024-05-08 14:53:53 -04:00
UMetaSoundAssetSubsystem & UMetaSoundAssetSubsystem : : GetChecked ( )
2021-11-07 23:43:01 -05:00
{
2024-05-08 14:53:53 -04:00
check ( GEngine ) ;
UMetaSoundAssetSubsystem * Subsystem = GEngine - > GetEngineSubsystem < UMetaSoundAssetSubsystem > ( ) ;
check ( Subsystem ) ;
return * Subsystem ;
2021-11-18 14:37:34 -05:00
}
2024-09-10 10:26:02 -04:00
# if WITH_EDITOR
bool UMetaSoundAssetSubsystem : : ReassignClassName ( TScriptInterface < IMetaSoundDocumentInterface > DocInterface )
{
using namespace Metasound : : Engine ;
return FMetaSoundAssetManager : : GetChecked ( ) . ReassignClassName ( DocInterface ) ;
}
# endif // WITH_EDITOR
2021-11-18 14:37:34 -05:00
void UMetaSoundAssetSubsystem : : RegisterAssetClassesInDirectories ( const TArray < FMetaSoundAssetDirectory > & InDirectories )
{
2024-05-08 14:53:53 -04:00
using namespace Metasound : : Engine ;
FMetaSoundAssetManager : : GetChecked ( ) . RegisterAssetClassesInDirectories ( InDirectories ) ;
2021-11-18 14:37:34 -05:00
}
2024-09-10 10:26:02 -04:00
# if WITH_EDITOR
bool UMetaSoundAssetSubsystem : : ReplaceReferencesInDirectory (
const TArray < FMetaSoundAssetDirectory > & InDirectories ,
const FMetasoundFrontendClassName & OldClassName ,
const FMetasoundFrontendClassName & NewClassName ,
const FMetasoundFrontendVersionNumber OldVersion ,
const FMetasoundFrontendVersionNumber NewVersion )
{
using namespace Metasound : : Engine ;
using namespace Metasound : : Frontend ;
return FMetaSoundAssetManager : : GetChecked ( ) . ReplaceReferencesInDirectory (
InDirectories ,
FNodeRegistryKey ( EMetasoundFrontendClassType : : External , OldClassName , OldVersion ) ,
FNodeRegistryKey ( EMetasoundFrontendClassType : : External , NewClassName , NewVersion )
) ;
}
# endif // WITH_EDITOR
2021-11-18 14:37:34 -05:00
void UMetaSoundAssetSubsystem : : UnregisterAssetClassesInDirectories ( const TArray < FMetaSoundAssetDirectory > & InDirectories )
{
2024-05-08 14:53:53 -04:00
using namespace Metasound : : Engine ;
FMetaSoundAssetManager : : GetChecked ( ) . UnregisterAssetClassesInDirectories ( InDirectories ) ;
2021-11-18 14:37:34 -05:00
}