2022-10-13 17:38:11 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# pragma once
# include "Metasound.h"
# include "MetasoundAssetManager.h"
2023-07-24 17:38:26 -04:00
# include "MetasoundBuilderSubsystem.h"
2023-08-21 12:25:01 -04:00
# include "MetasoundFrontendDocumentIdGenerator.h"
2023-12-19 15:55:04 -05:00
# include "MetasoundFrontendRegistryKey.h"
2022-10-13 17:38:11 -04:00
# include "MetasoundUObjectRegistry.h"
2024-02-12 12:54:06 -05:00
# include "Misc/App.h"
2022-10-13 17:38:11 -04:00
# include "Serialization/Archive.h"
# if WITH_EDITORONLY_DATA
# include "MetasoundFrontendRegistries.h"
# include "Algo/Transform.h"
# endif // WITH_EDITORONLY_DATA
namespace Metasound
{
/** MetaSound Engine Asset helper provides routines for UObject based MetaSound assets.
* Any UObject deriving from FMetaSoundAssetBase should use these helper functions
* in their UObject overrides .
*/
struct FMetaSoundEngineAssetHelper
{
# if WITH_EDITOR
template < typename TMetaSoundObject >
static void PostEditUndo ( TMetaSoundObject & InMetaSound )
{
InMetaSound . GetModifyContext ( ) . SetForceRefreshViews ( ) ;
2023-07-24 17:38:26 -04:00
const FMetasoundFrontendDocument & Document = InMetaSound . GetDocumentChecked ( ) ;
const FMetasoundFrontendClassName & ClassName = Document . RootGraph . Metadata . GetClassName ( ) ;
UMetaSoundBuilderSubsystem : : GetChecked ( ) . PostBuilderAssetTransaction ( ClassName ) ;
2022-10-13 17:38:11 -04:00
if ( UMetasoundEditorGraphBase * Graph = Cast < UMetasoundEditorGraphBase > ( InMetaSound . GetGraph ( ) ) )
{
Graph - > RegisterGraphWithFrontend ( ) ;
}
}
template < typename TMetaSoundObject >
2023-12-19 15:55:04 -05:00
static void SetReferencedAssetClasses ( TMetaSoundObject & InMetaSound , TSet < Frontend : : IMetaSoundAssetManager : : FAssetInfo > & & InAssetClasses )
2022-10-13 17:38:11 -04:00
{
2023-12-19 15:55:04 -05:00
using namespace Frontend ;
2022-10-13 17:38:11 -04:00
InMetaSound . ReferencedAssetClassKeys . Reset ( ) ;
InMetaSound . ReferencedAssetClassObjects . Reset ( ) ;
for ( const IMetaSoundAssetManager : : FAssetInfo & AssetClass : InAssetClasses )
{
2023-10-12 16:37:45 -04:00
InMetaSound . ReferencedAssetClassKeys . Add ( AssetClass . RegistryKey . ToString ( ) ) ;
2022-10-13 17:38:11 -04:00
if ( UObject * Object = AssetClass . AssetPath . TryLoad ( ) )
{
InMetaSound . ReferencedAssetClassObjects . Add ( Object ) ;
}
else
{
UE_LOG ( LogMetaSound , Error , TEXT ( " Failed to load referenced asset %s from asset %s " ) , * AssetClass . AssetPath . ToString ( ) , * InMetaSound . GetPathName ( ) ) ;
}
}
}
# endif // WITH_EDITOR
2023-12-15 13:21:12 -05:00
template < typename TMetaSoundObject >
static FTopLevelAssetPath GetAssetPathChecked ( TMetaSoundObject & InMetaSound )
{
FTopLevelAssetPath Path ;
2024-01-08 17:02:57 -05:00
ensureAlwaysMsgf ( Path . TrySetPath ( & InMetaSound ) , TEXT ( " Failed to set TopLevelAssetPath from MetaSound '%s'. MetaSound must be highest level object in package. " ) , * InMetaSound . GetPathName ( ) ) ;
ensureAlwaysMsgf ( Path . IsValid ( ) , TEXT ( " Failed to set TopLevelAssetPath from MetaSound '%s'. This may be caused by calling this function when the asset is being destroyed. " ) , * InMetaSound . GetPathName ( ) ) ;
2023-12-15 13:21:12 -05:00
return Path ;
}
2022-10-13 17:38:11 -04:00
template < typename TMetaSoundObject >
static TArray < FMetasoundAssetBase * > GetReferencedAssets ( TMetaSoundObject & InMetaSound )
{
TArray < FMetasoundAssetBase * > ReferencedAssets ;
IMetasoundUObjectRegistry & UObjectRegistry = IMetasoundUObjectRegistry : : Get ( ) ;
for ( TObjectPtr < UObject > & Object : InMetaSound . ReferencedAssetClassObjects )
{
if ( FMetasoundAssetBase * Asset = UObjectRegistry . GetObjectAsAssetBase ( Object ) )
{
ReferencedAssets . Add ( Asset ) ;
}
else
{
UE_LOG ( LogMetaSound , Error , TEXT ( " Referenced asset \" %s \" , referenced from \" %s \" , is not convertible to FMetasoundAssetBase " ) , * Object - > GetPathName ( ) , * InMetaSound . GetPathName ( ) ) ;
}
}
return ReferencedAssets ;
}
template < typename TMetaSoundObject >
static void PreSaveAsset ( TMetaSoundObject & InMetaSound , FObjectPreSaveContext InSaveContext )
{
# if WITH_EDITORONLY_DATA
2023-12-19 15:55:04 -05:00
using namespace Frontend ;
2022-10-13 17:38:11 -04:00
2022-11-17 12:31:19 -05:00
// Do not call asset manager on CDO objects which may be loaded before asset
// manager is set.
if ( IMetaSoundAssetManager * AssetManager = IMetaSoundAssetManager : : Get ( ) )
{
AssetManager - > WaitUntilAsyncLoadReferencedAssetsComplete ( InMetaSound ) ;
}
2022-10-13 17:38:11 -04:00
if ( UMetasoundEditorGraphBase * MetaSoundGraph = Cast < UMetasoundEditorGraphBase > ( InMetaSound . GetGraph ( ) ) )
{
2024-02-12 12:54:06 -05:00
if ( InSaveContext . IsCooking ( ) | | IsRunningCommandlet ( ) )
2023-08-21 12:25:01 -04:00
{
// Use deterministic ID generation so more can be done at cook rather than runtime
if ( MetaSoundEnableCookDeterministicIDGeneration ! = 0 )
{
{
constexpr bool bIsDeterministic = true ;
FDocumentIDGenerator : : FScopeDeterminism DeterminismScope = FDocumentIDGenerator : : FScopeDeterminism ( bIsDeterministic ) ;
2023-09-05 17:54:02 -04:00
InMetaSound . CookMetaSound ( ) ;
2023-08-21 12:25:01 -04:00
}
}
}
2024-02-12 12:54:06 -05:00
else if ( FApp : : CanEverRenderAudio ( ) )
2022-10-13 17:38:11 -04:00
{
MetaSoundGraph - > RegisterGraphWithFrontend ( ) ;
MetaSoundGraph - > GetModifyContext ( ) . SetForceRefreshViews ( ) ;
}
2024-02-12 12:54:06 -05:00
else
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " PreSaveAsset for MetaSound: (%s) is doing nothing because InSaveContext.IsCooking, IsRunningCommandlet, and FApp::CanEverRenderAudio were all false " )
, * InMetaSound . GetPathName ( ) ) ;
}
2022-10-13 17:38:11 -04:00
}
# endif // WITH_EDITORONLY_DATA
}
template < typename TMetaSoundObject >
static void SerializeToArchive ( TMetaSoundObject & InMetaSound , FArchive & InArchive )
{
if ( InArchive . IsLoading ( ) )
{
if ( InMetaSound . VersionAsset ( ) )
{
# if WITH_EDITORONLY_DATA
if ( UMetasoundEditorGraphBase * MetaSoundGraph = Cast < UMetasoundEditorGraphBase > ( InMetaSound . GetGraph ( ) ) )
{
MetaSoundGraph - > SetVersionedOnLoad ( ) ;
}
# endif // WITH_EDITORONLY_DATA
}
}
}
template < typename TMetaSoundObject >
static void PostLoad ( TMetaSoundObject & InMetaSound )
{
2022-10-14 10:55:37 -04:00
using namespace Frontend ;
// Do not call asset manager on CDO objects which may be loaded before asset
// manager is set.
const bool bIsCDO = InMetaSound . HasAnyFlags ( RF_ClassDefaultObject ) ;
if ( ! bIsCDO )
{
2022-10-17 12:46:38 -04:00
if ( InMetaSound . GetAsyncReferencedAssetClassPaths ( ) . Num ( ) > 0 )
2022-10-14 10:55:37 -04:00
{
2022-10-17 12:46:38 -04:00
if ( IMetaSoundAssetManager * AssetManager = IMetaSoundAssetManager : : Get ( ) )
{
AssetManager - > RequestAsyncLoadReferencedAssets ( InMetaSound ) ;
}
else
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Request for to load async references ignored from asset %s. Likely due loading before the MetaSoundEngine module. " ) , * InMetaSound . GetPathName ( ) ) ;
}
2022-10-14 10:55:37 -04:00
}
}
2022-10-13 17:38:11 -04:00
}
template < typename TMetaSoundObject >
static void OnAsyncReferencedAssetsLoaded ( TMetaSoundObject & InMetaSound , const TArray < FMetasoundAssetBase * > & InAsyncReferences )
{
for ( FMetasoundAssetBase * AssetBase : InAsyncReferences )
{
if ( AssetBase )
{
if ( UObject * OwningAsset = AssetBase - > GetOwningAsset ( ) )
{
InMetaSound . ReferencedAssetClassObjects . Add ( OwningAsset ) ;
InMetaSound . ReferenceAssetClassCache . Remove ( FSoftObjectPath ( OwningAsset ) ) ;
}
}
}
}
# if WITH_EDITORONLY_DATA
template < typename TMetaSoundObject >
2023-12-19 15:55:04 -05:00
static void SetMetaSoundRegistryAssetClassInfo ( TMetaSoundObject & InMetaSound , const Frontend : : FNodeClassInfo & InClassInfo )
2022-10-13 17:38:11 -04:00
{
2023-12-19 15:55:04 -05:00
using namespace Frontend ;
2022-10-13 17:38:11 -04:00
check ( AssetTags : : AssetClassID = = GET_MEMBER_NAME_CHECKED ( TMetaSoundObject , AssetClassID ) ) ;
2022-10-26 15:28:04 -04:00
check ( AssetTags : : IsPreset = = GET_MEMBER_NAME_CHECKED ( TMetaSoundObject , bIsPreset ) ) ;
2022-10-13 17:38:11 -04:00
check ( AssetTags : : RegistryInputTypes = = GET_MEMBER_NAME_CHECKED ( TMetaSoundObject , RegistryInputTypes ) ) ;
check ( AssetTags : : RegistryOutputTypes = = GET_MEMBER_NAME_CHECKED ( TMetaSoundObject , RegistryOutputTypes ) ) ;
check ( AssetTags : : RegistryVersionMajor = = GET_MEMBER_NAME_CHECKED ( TMetaSoundObject , RegistryVersionMajor ) ) ;
check ( AssetTags : : RegistryVersionMinor = = GET_MEMBER_NAME_CHECKED ( TMetaSoundObject , RegistryVersionMinor ) ) ;
bool bMarkDirty = InMetaSound . AssetClassID ! = InClassInfo . AssetClassID ;
bMarkDirty | = InMetaSound . RegistryVersionMajor ! = InClassInfo . Version . Major ;
bMarkDirty | = InMetaSound . RegistryVersionMinor ! = InClassInfo . Version . Minor ;
2022-10-26 15:28:04 -04:00
bMarkDirty | = InMetaSound . bIsPreset ! = InClassInfo . bIsPreset ;
2022-10-13 17:38:11 -04:00
InMetaSound . AssetClassID = InClassInfo . AssetClassID ;
InMetaSound . RegistryVersionMajor = InClassInfo . Version . Major ;
InMetaSound . RegistryVersionMinor = InClassInfo . Version . Minor ;
2022-10-26 15:28:04 -04:00
InMetaSound . bIsPreset = InClassInfo . bIsPreset ;
2022-10-13 17:38:11 -04:00
{
TArray < FString > InputTypes ;
Algo : : Transform ( InClassInfo . InputTypes , InputTypes , [ ] ( const FName & Name ) { return Name . ToString ( ) ; } ) ;
const FString TypeString = FString : : Join ( InputTypes , * AssetTags : : ArrayDelim ) ;
bMarkDirty | = InMetaSound . RegistryInputTypes ! = TypeString ;
InMetaSound . RegistryInputTypes = TypeString ;
}
{
TArray < FString > OutputTypes ;
Algo : : Transform ( InClassInfo . OutputTypes , OutputTypes , [ ] ( const FName & Name ) { return Name . ToString ( ) ; } ) ;
const FString TypeString = FString : : Join ( OutputTypes , * AssetTags : : ArrayDelim ) ;
bMarkDirty | = InMetaSound . RegistryOutputTypes ! = TypeString ;
InMetaSound . RegistryOutputTypes = TypeString ;
}
}
# endif // WITH_EDITORONLY_DATA
} ;
} // namespace Metasound