2021-03-15 14:00:26 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# pragma once
2024-05-07 16:54:01 -04:00
# include "Concepts/GetTypeHashable.h"
2021-04-05 20:22:19 -04:00
# include "Containers/CircularQueue.h"
2022-08-19 12:14:31 -04:00
# include "Interfaces/MetasoundFrontendSourceInterface.h"
2024-05-07 16:54:01 -04:00
# include "Templates/Models.h"
2021-04-05 20:22:19 -04:00
# include "MetasoundArrayNodes.h"
2024-05-07 16:54:01 -04:00
# include "MetasoundEnum.h"
2021-04-05 20:22:19 -04:00
# include "MetasoundExecutableOperator.h"
2021-03-15 14:00:26 -04:00
# include "MetasoundFacade.h"
# include "MetasoundNodeInterface.h"
2024-05-07 16:54:01 -04:00
# include "MetasoundOperatorBuilder.h"
2022-03-17 13:14:50 -04:00
# include "MetasoundParamHelper.h"
2021-03-29 23:58:06 -04:00
# include "MetasoundTrigger.h"
2021-03-15 14:00:26 -04:00
2022-01-18 17:44:56 -05:00
# define LOCTEXT_NAMESPACE "MetasoundFrontend"
2021-03-15 14:00:26 -04:00
2024-05-07 16:54:01 -04:00
namespace MetasoundArrayHashPrivate
{
template < typename ElementType >
FGuid GetArrayContentHashGuid ( const TArray < ElementType > & InArray )
{
if constexpr ( TModels_V < CGetTypeHashable , ElementType > )
{
uint32 A = GetTypeHash ( Metasound : : GetMetasoundDataTypeName < ElementType > ( ) ) ;
uint32 B = A ; uint32 C = A ; uint32 D = A ;
for ( int32 i = 0 ; i < InArray . Num ( ) ; i + + )
{
const int32 Pos = i % 4 ;
switch ( Pos )
{
case 0 :
A = HashCombineFast ( A , GetTypeHash ( InArray [ i ] ) ) ;
break ;
case 1 :
B = HashCombineFast ( B , GetTypeHash ( InArray [ i ] ) ) ;
break ;
case 2 :
C = HashCombineFast ( C , GetTypeHash ( InArray [ i ] ) ) ;
break ;
case 3 :
D = HashCombineFast ( D , GetTypeHash ( InArray [ i ] ) ) ;
break ;
}
}
return FGuid ( A , B , C , D ) ;
}
else
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Array Random Get: Please implement \" uint32 GetTypeHash(const T&) \" for type %s to use Same Data for Shared State Behavior. " ) , * Metasound : : GetMetasoundDataTypeString < ElementType > ( ) ) ;
return FGuid ( ) ;
}
}
}
2021-03-15 14:00:26 -04:00
namespace Metasound
{
namespace ArrayNodeRandomGetVertexNames
{
2022-03-17 13:14:50 -04:00
METASOUND_PARAM ( InputTriggerNextValue , " Next " , " Trigger to get the next value in the randomized array. " )
METASOUND_PARAM ( InputTriggerResetSeed , " Reset " , " Trigger to reset the seed for the randomized array. " )
2024-05-07 16:54:01 -04:00
METASOUND_PARAM ( InputRandomArray , " In Array " , " Input array to randomize. " )
2022-03-17 13:14:50 -04:00
METASOUND_PARAM ( InputWeights , " Weights " , " Input array of weights to use for random selection. Will repeat if this array is shorter than the input array to select from. " )
2024-05-07 16:54:01 -04:00
METASOUND_PARAM ( InputSeed , " Seed " , " Seed to use for the random stream. Set to -1 to use a random seed. " )
2022-03-17 13:14:50 -04:00
METASOUND_PARAM ( InputNoRepeatOrder , " No Repeats " , " The number of elements to track to avoid repeating in a row. " )
2024-05-07 16:54:01 -04:00
METASOUND_PARAM ( InputEnableSharedState , " Enable Shared State " , " Set to enabled to share state with other Random Get (Array) nodes. Does not apply when previewing in the MetaSound editor; use PIE or game. " )
METASOUND_PARAM ( InputSharedStateBehavior , " Shared State Behavior " , " The behavior for how state is shared with other Random Get (Array) nodes. Only applied when Enable Shared State is true. " )
2022-03-17 13:14:50 -04:00
METASOUND_PARAM ( OutputTriggerOnNext , " On Next " , " Triggers when the \" Next \" input is triggered. " )
2024-05-07 16:54:01 -04:00
METASOUND_PARAM ( OutputTriggerOnReset , " On Reset " , " Triggers when the \" Reset \" input is triggered. " )
METASOUND_PARAM ( ShuffleOutputValue , " Value " , " Value of the current random element. " )
METASOUND_PARAM ( OutputIndex , " Index " , " Array index of the current random element. " )
2021-03-15 14:00:26 -04:00
}
2024-05-07 16:54:01 -04:00
enum class ESharedStateBehaviorType : int32
{
SameNode ,
SameNodeInComposition ,
SameData
} ;
DECLARE_METASOUND_ENUM ( ESharedStateBehaviorType , ESharedStateBehaviorType : : SameNodeInComposition , METASOUNDFRONTEND_API ,
FEnumSharedStateBehaviorType , FEnumSharedStateBehaviorTypeInfo , FEnumSharedStateBehaviorTypeReadRef , FSharedStateBehaviorTypeWriteRef ) ;
2021-03-15 14:00:26 -04:00
class METASOUNDFRONTEND_API FArrayRandomGet
{
public :
FArrayRandomGet ( ) = default ;
2021-03-29 23:58:06 -04:00
FArrayRandomGet ( int32 InSeed , int32 InMaxIndex , const TArray < float > & InWeights , int32 InNoRepeatOrder ) ;
~ FArrayRandomGet ( ) = default ;
2024-05-07 16:54:01 -04:00
UE_DEPRECATED ( 5.5 , " Use UpdateState instead " )
2021-03-29 23:58:06 -04:00
void Init ( int32 InSeed , int32 InMaxIndex , const TArray < float > & InWeights , int32 InNoRepeatOrder ) ;
2024-05-07 16:54:01 -04:00
void UpdateState ( int32 InSeed , int32 InMaxIndex , const TArray < float > & InWeights , int32 InNoRepeatOrder ) ;
2021-03-15 14:00:26 -04:00
void SetSeed ( int32 InSeed ) ;
void SetNoRepeatOrder ( int32 InNoRepeatOrder ) ;
2021-03-29 23:58:06 -04:00
void SetRandomWeights ( const TArray < float > & InRandomWeights ) ;
2021-03-15 14:00:26 -04:00
void ResetSeed ( ) ;
int32 NextValue ( ) ;
2022-03-01 21:24:51 -05:00
int32 GetNoRepeatOrder ( ) const { return NoRepeatOrder ; }
int32 GetMaxIndex ( ) const { return MaxIndex ; }
2021-03-15 14:00:26 -04:00
private :
2021-03-29 23:58:06 -04:00
float ComputeTotalWeight ( ) ;
2021-03-15 14:00:26 -04:00
// The current index into the array of indicies (wraps between 0 and ShuffleIndices.Num())
TArray < int32 > PreviousIndices ;
TUniquePtr < TCircularQueue < int32 > > PreviousIndicesQueue ;
2021-03-22 08:31:34 -04:00
int32 NoRepeatOrder = INDEX_NONE ;
2021-03-15 14:00:26 -04:00
// Array of indices (in order 0 to Num)
int32 MaxIndex = 0 ;
TArray < float > RandomWeights ;
// Random stream to use to randomize the shuffling
FRandomStream RandomStream ;
2024-05-07 16:54:01 -04:00
int32 Seed = INDEX_NONE ;
bool bRandomStreamInitialized = false ;
2021-03-15 14:00:26 -04:00
} ;
2021-04-03 18:41:39 -04:00
struct InitSharedStateArgs
{
2022-02-04 18:18:22 -05:00
FGuid SharedStateId ;
2021-04-03 18:41:39 -04:00
int32 Seed = INDEX_NONE ;
int32 NumElements = 0 ;
int32 NoRepeatOrder = 0 ;
bool bIsPreviewSound = false ;
TArray < float > Weights ;
} ;
2021-03-15 14:00:26 -04:00
class METASOUNDFRONTEND_API FSharedStateRandomGetManager
{
public :
static FSharedStateRandomGetManager & Get ( ) ;
2021-04-03 18:41:39 -04:00
void InitSharedState ( InitSharedStateArgs & InArgs ) ;
2024-05-07 16:54:01 -04:00
// Initialize or update state for a given shared state id. No lock, so call this function within one if needed
void InitOrUpdate ( InitSharedStateArgs & InStateArgs ) ;
// Get the next array index
// Init or update state with the given args, then return next value (within a single lock operation)
int32 NextValue ( const FGuid & InSharedStateId , InitSharedStateArgs & InStateArgs ) ;
2022-02-04 18:18:22 -05:00
int32 NextValue ( const FGuid & InSharedStateId ) ;
2024-05-07 16:54:01 -04:00
2022-02-04 18:18:22 -05:00
void SetSeed ( const FGuid & InSharedStateId , int32 InSeed ) ;
void SetNoRepeatOrder ( const FGuid & InSharedStateId , int32 InNoRepeatOrder ) ;
void SetRandomWeights ( const FGuid & InSharedStateId , const TArray < float > & InRandomWeights ) ;
2024-05-07 16:54:01 -04:00
// Init or update state with the given args, then reset seed (within a single lock operation)
void ResetSeed ( const FGuid & InSharedStateId , InitSharedStateArgs & InStateArgs ) ;
2022-02-04 18:18:22 -05:00
void ResetSeed ( const FGuid & InSharedStateId ) ;
2021-03-15 14:00:26 -04:00
2024-05-07 16:54:01 -04:00
2021-03-15 14:00:26 -04:00
private :
FSharedStateRandomGetManager ( ) = default ;
~ FSharedStateRandomGetManager ( ) = default ;
FCriticalSection CritSect ;
2022-02-04 18:18:22 -05:00
TMap < FGuid , TUniquePtr < FArrayRandomGet > > RandomGets ;
2021-03-15 14:00:26 -04:00
} ;
template < typename ArrayType >
class TArrayRandomGetOperator : public TExecutableOperator < TArrayRandomGetOperator < ArrayType > >
{
public :
using FArrayDataReadReference = TDataReadReference < ArrayType > ;
2021-03-29 23:58:06 -04:00
using FArrayWeightReadReference = TDataReadReference < TArray < float > > ;
2021-04-03 18:41:39 -04:00
using WeightsArrayType = TArray < float > ;
2021-03-15 14:00:26 -04:00
using ElementType = typename MetasoundArrayNodesPrivate : : TArrayElementType < ArrayType > : : Type ;
using FElementTypeWriteReference = TDataWriteReference < ElementType > ;
static const FVertexInterface & GetDefaultInterface ( )
{
using namespace ArrayNodeRandomGetVertexNames ;
static const FVertexInterface DefaultInterface (
FInputVertexInterface (
2022-03-31 16:49:59 -04:00
TInputDataVertex < FTrigger > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InputTriggerNextValue ) ) ,
TInputDataVertex < FTrigger > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InputTriggerResetSeed ) ) ,
TInputDataVertex < ArrayType > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InputRandomArray ) ) ,
TInputDataVertex < WeightsArrayType > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InputWeights ) ) ,
TInputDataVertex < int32 > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InputSeed ) , - 1 ) ,
TInputDataVertex < int32 > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InputNoRepeatOrder ) , 1 ) ,
2024-05-07 16:54:01 -04:00
TInputDataVertex < bool > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InputEnableSharedState ) , false ) ,
TInputConstructorVertex < FEnumSharedStateBehaviorType > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InputSharedStateBehavior ) , ( int32 ) ESharedStateBehaviorType : : SameNodeInComposition )
2021-03-15 14:00:26 -04:00
) ,
FOutputVertexInterface (
2022-03-31 16:49:59 -04:00
TOutputDataVertex < FTrigger > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( OutputTriggerOnNext ) ) ,
TOutputDataVertex < FTrigger > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( OutputTriggerOnReset ) ) ,
2024-05-07 16:54:01 -04:00
TOutputDataVertex < ElementType > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( ShuffleOutputValue ) ) ,
TOutputDataVertex < int32 > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( OutputIndex ) )
2021-03-15 14:00:26 -04:00
)
) ;
return DefaultInterface ;
}
static const FNodeClassMetadata & GetNodeInfo ( )
{
auto CreateNodeClassMetadata = [ ] ( ) - > FNodeClassMetadata
{
FName DataTypeName = GetMetasoundDataTypeName < ArrayType > ( ) ;
2021-05-10 16:56:43 -04:00
FName OperatorName = " Random Get " ;
2022-02-10 18:36:47 -05:00
FText NodeDisplayName = METASOUND_LOCTEXT_FORMAT ( " RandomArrayGetNode_OpDisplayNamePattern " , " Random Get ({0}) " , GetMetasoundDataTypeDisplayText < ArrayType > ( ) ) ;
FText NodeDescription = METASOUND_LOCTEXT ( " RandomArrayGetNode_Description " , " Randomly retrieve data from input array using the supplied weights. " ) ;
2021-03-15 14:00:26 -04:00
FVertexInterface NodeInterface = GetDefaultInterface ( ) ;
2024-05-07 16:54:01 -04:00
return MetasoundArrayNodesPrivate : : CreateArrayNodeClassMetadata ( DataTypeName , OperatorName , NodeDisplayName , NodeDescription , NodeInterface , /*MajorVersion=*/ 1 , /*MinorVersion=*/ 1 ) ;
2021-03-15 14:00:26 -04:00
} ;
static const FNodeClassMetadata Metadata = CreateNodeClassMetadata ( ) ;
return Metadata ;
}
2023-10-13 19:29:51 -04:00
static TUniquePtr < IOperator > CreateOperator ( const FBuildOperatorParams & InParams , FBuildResults & OutResults )
2021-03-15 14:00:26 -04:00
{
using namespace ArrayNodeRandomGetVertexNames ;
using namespace MetasoundArrayNodesPrivate ;
2023-10-13 19:29:51 -04:00
const FInputVertexInterfaceData & InputData = InParams . InputData ;
2021-03-15 14:00:26 -04:00
2023-10-13 19:29:51 -04:00
FTriggerReadRef InTriggerNext = InputData . GetOrCreateDefaultDataReadReference < FTrigger > ( METASOUND_GET_PARAM_NAME ( InputTriggerNextValue ) , InParams . OperatorSettings ) ;
FTriggerReadRef InTriggerReset = InputData . GetOrCreateDefaultDataReadReference < FTrigger > ( METASOUND_GET_PARAM_NAME ( InputTriggerResetSeed ) , InParams . OperatorSettings ) ;
FArrayDataReadReference InInputArray = InputData . GetOrCreateDefaultDataReadReference < ArrayType > ( METASOUND_GET_PARAM_NAME ( InputRandomArray ) , InParams . OperatorSettings ) ;
FArrayWeightReadReference InInputWeightsArray = InputData . GetOrCreateDefaultDataReadReference < WeightsArrayType > ( METASOUND_GET_PARAM_NAME ( InputWeights ) , InParams . OperatorSettings ) ;
FInt32ReadRef InSeedValue = InputData . GetOrCreateDefaultDataReadReference < int32 > ( METASOUND_GET_PARAM_NAME ( InputSeed ) , InParams . OperatorSettings ) ;
FInt32ReadRef InNoRepeatOrder = InputData . GetOrCreateDefaultDataReadReference < int32 > ( METASOUND_GET_PARAM_NAME ( InputNoRepeatOrder ) , InParams . OperatorSettings ) ;
FBoolReadRef bInEnableSharedState = InputData . GetOrCreateDefaultDataReadReference < bool > ( METASOUND_GET_PARAM_NAME ( InputEnableSharedState ) , InParams . OperatorSettings ) ;
2024-05-07 16:54:01 -04:00
FEnumSharedStateBehaviorType InSharedStateBehavior = InputData . GetOrCreateDefaultValue < FEnumSharedStateBehaviorType > ( METASOUND_GET_PARAM_NAME ( InputSharedStateBehavior ) , InParams . OperatorSettings ) ;
2021-03-15 14:00:26 -04:00
2024-05-07 16:54:01 -04:00
return MakeUnique < TArrayRandomGetOperator < ArrayType > > ( InParams , InTriggerNext , InTriggerReset , InInputArray , InInputWeightsArray , InSeedValue , InNoRepeatOrder , bInEnableSharedState , InSharedStateBehavior ) ;
2021-03-15 14:00:26 -04:00
}
TArrayRandomGetOperator (
2023-10-13 19:29:51 -04:00
const FBuildOperatorParams & InParams ,
2021-03-15 14:00:26 -04:00
const FTriggerReadRef & InTriggerNext ,
const FTriggerReadRef & InTriggerReset ,
const FArrayDataReadReference & InInputArray ,
2021-04-03 18:41:39 -04:00
const TDataReadReference < WeightsArrayType > & InInputWeightsArray ,
2021-03-15 14:00:26 -04:00
const FInt32ReadRef & InSeedValue ,
const FInt32ReadRef & InNoRepeatOrder ,
2024-05-07 16:54:01 -04:00
const FBoolReadRef & bInEnableSharedState ,
const FEnumSharedStateBehaviorType InSharedStateBehavior )
2021-03-15 14:00:26 -04:00
: TriggerNext ( InTriggerNext )
, TriggerReset ( InTriggerReset )
, InputArray ( InInputArray )
, InputWeightsArray ( InInputWeightsArray )
, SeedValue ( InSeedValue )
, NoRepeatOrder ( InNoRepeatOrder )
2024-05-07 16:54:01 -04:00
, bEnableSharedState ( bInEnableSharedState )
, SharedStateBehavior ( InSharedStateBehavior )
2021-03-15 14:00:26 -04:00
, TriggerOnNext ( FTriggerWriteRef : : CreateNew ( InParams . OperatorSettings ) )
, TriggerOnReset ( FTriggerWriteRef : : CreateNew ( InParams . OperatorSettings ) )
, OutValue ( TDataWriteReferenceFactory < ElementType > : : CreateAny ( InParams . OperatorSettings ) )
2024-05-07 16:54:01 -04:00
, OutIndex ( FInt32WriteRef : : CreateNew ( INDEX_NONE ) )
2021-12-10 19:13:22 -05:00
{
2024-05-07 16:54:01 -04:00
NodeId = InParams . Node . GetInstanceID ( ) ;
2023-02-22 17:54:26 -05:00
Reset ( InParams ) ;
2021-03-15 14:00:26 -04:00
}
virtual ~ TArrayRandomGetOperator ( ) = default ;
[Metasound Bind] Fixup for bind issues caught by new automated tests.
#jira UE-187406, UE-187390, UE-187404, UE-187403, UE-187405, UE-187392, UE-187391, UE-187395, UE-187399, UE-187398, UE-187389, UE-187393, UE-187394, UE-187396, UE-187397, UE-187401
#rb phil.popp
[CL 26130674 by maxwell hayes in ue5-main branch]
2023-06-20 15:08:54 -04:00
virtual void BindInputs ( FInputVertexInterfaceData & InOutVertexData ) override
{
using namespace ArrayNodeRandomGetVertexNames ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InputTriggerNextValue ) , TriggerNext ) ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InputTriggerResetSeed ) , TriggerReset ) ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InputRandomArray ) , InputArray ) ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InputWeights ) , InputWeightsArray ) ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InputSeed ) , SeedValue ) ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InputNoRepeatOrder ) , NoRepeatOrder ) ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InputEnableSharedState ) , bEnableSharedState ) ;
2024-05-07 16:54:01 -04:00
InOutVertexData . SetValue ( METASOUND_GET_PARAM_NAME ( InputSharedStateBehavior ) , SharedStateBehavior ) ;
[Metasound Bind] Fixup for bind issues caught by new automated tests.
#jira UE-187406, UE-187390, UE-187404, UE-187403, UE-187405, UE-187392, UE-187391, UE-187395, UE-187399, UE-187398, UE-187389, UE-187393, UE-187394, UE-187396, UE-187397, UE-187401
#rb phil.popp
[CL 26130674 by maxwell hayes in ue5-main branch]
2023-06-20 15:08:54 -04:00
}
virtual void BindOutputs ( FOutputVertexInterfaceData & InOutVertexData ) override
{
using namespace ArrayNodeRandomGetVertexNames ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( OutputTriggerOnNext ) , TriggerOnNext ) ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( OutputTriggerOnReset ) , TriggerOnReset ) ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( ShuffleOutputValue ) , OutValue ) ;
2024-05-07 16:54:01 -04:00
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( OutputIndex ) , OutIndex ) ;
[Metasound Bind] Fixup for bind issues caught by new automated tests.
#jira UE-187406, UE-187390, UE-187404, UE-187403, UE-187405, UE-187392, UE-187391, UE-187395, UE-187399, UE-187398, UE-187389, UE-187393, UE-187394, UE-187396, UE-187397, UE-187401
#rb phil.popp
[CL 26130674 by maxwell hayes in ue5-main branch]
2023-06-20 15:08:54 -04:00
}
2021-03-15 14:00:26 -04:00
virtual FDataReferenceCollection GetInputs ( ) const override
{
[Metasound Bind] Fixup for bind issues caught by new automated tests.
#jira UE-187406, UE-187390, UE-187404, UE-187403, UE-187405, UE-187392, UE-187391, UE-187395, UE-187399, UE-187398, UE-187389, UE-187393, UE-187394, UE-187396, UE-187397, UE-187401
#rb phil.popp
[CL 26130674 by maxwell hayes in ue5-main branch]
2023-06-20 15:08:54 -04:00
// This should never be called. Bind(...) is called instead. This method
// exists as a stop-gap until the API can be deprecated and removed.
2023-04-17 15:20:55 -04:00
checkNoEntry ( ) ;
[Metasound Bind] Fixup for bind issues caught by new automated tests.
#jira UE-187406, UE-187390, UE-187404, UE-187403, UE-187405, UE-187392, UE-187391, UE-187395, UE-187399, UE-187398, UE-187389, UE-187393, UE-187394, UE-187396, UE-187397, UE-187401
#rb phil.popp
[CL 26130674 by maxwell hayes in ue5-main branch]
2023-06-20 15:08:54 -04:00
return { } ;
2021-03-15 14:00:26 -04:00
}
virtual FDataReferenceCollection GetOutputs ( ) const override
2023-04-17 15:20:55 -04:00
{
[Metasound Bind] Fixup for bind issues caught by new automated tests.
#jira UE-187406, UE-187390, UE-187404, UE-187403, UE-187405, UE-187392, UE-187391, UE-187395, UE-187399, UE-187398, UE-187389, UE-187393, UE-187394, UE-187396, UE-187397, UE-187401
#rb phil.popp
[CL 26130674 by maxwell hayes in ue5-main branch]
2023-06-20 15:08:54 -04:00
// This should never be called. Bind(...) is called instead. This method
// exists as a stop-gap until the API can be deprecated and removed.
2023-04-17 15:20:55 -04:00
checkNoEntry ( ) ;
[Metasound Bind] Fixup for bind issues caught by new automated tests.
#jira UE-187406, UE-187390, UE-187404, UE-187403, UE-187405, UE-187392, UE-187391, UE-187395, UE-187399, UE-187398, UE-187389, UE-187393, UE-187394, UE-187396, UE-187397, UE-187401
#rb phil.popp
[CL 26130674 by maxwell hayes in ue5-main branch]
2023-06-20 15:08:54 -04:00
return { } ;
2021-03-15 14:00:26 -04:00
}
2023-02-22 17:54:26 -05:00
void Reset ( const IOperator : : FResetParams & InParams )
{
using namespace Frontend ;
# if WITH_METASOUND_DEBUG_ENVIRONMENT
if ( InParams . Environment . Contains < FString > ( SourceInterface : : Environment : : GraphName ) )
{
GraphName = * InParams . Environment . GetValue < FString > ( SourceInterface : : Environment : : GraphName ) ;
}
2024-05-07 16:54:01 -04:00
TOptional < FName > EnumName = FEnumSharedStateBehaviorType : : ToName ( SharedStateBehavior ) ;
if ( EnumName . IsSet ( ) )
{
DebugSharedStateBehaviorString = EnumName . GetValue ( ) . ToString ( ) ;
}
2023-02-22 17:54:26 -05:00
# endif // WITH_METASOUND_DEBUG_ENVIRONMENT
bIsPreviewSound = InParams . Environment . GetValue < bool > ( SourceInterface : : Environment : : IsPreview ) ;
2023-12-20 12:45:12 -05:00
2023-02-22 17:54:26 -05:00
* OutValue = TDataTypeFactory < ElementType > : : CreateAny ( InParams . OperatorSettings ) ;
2024-05-07 16:54:01 -04:00
* OutIndex = INDEX_NONE ;
2023-02-22 17:54:26 -05:00
TriggerOnNext - > Reset ( ) ;
TriggerOnReset - > Reset ( ) ;
2024-05-07 16:54:01 -04:00
// Cache shared state id for shared state behavior types that cannot be changed after node init
2024-05-30 19:36:18 -04:00
if ( InParams . Environment . Contains < TArray < FGuid > > ( CoreInterface : : Environment : : GraphHierarchy ) )
2024-05-07 16:54:01 -04:00
{
2024-05-30 19:36:18 -04:00
const TArray < FGuid > & GraphHierarchy = InParams . Environment . GetValue < TArray < FGuid > > ( CoreInterface : : Environment : : GraphHierarchy ) ;
2024-05-24 14:33:22 -04:00
if ( SharedStateBehavior = = ESharedStateBehaviorType : : SameNode )
{
check ( GraphHierarchy . Num ( ) > 0 ) ;
// Hash node id with this node's graph id because node ids are not guaranteed to be unique
// (they are not regenerated when duplicating assets)
SharedStateId = GetSameNodeSharedStateId ( NodeId , GraphHierarchy . Last ( ) ) ;
}
else if ( SharedStateBehavior = = ESharedStateBehaviorType : : SameNodeInComposition )
2024-05-07 16:54:01 -04:00
{
SharedStateId = GetSameNodeInCompositionId ( NodeId , GraphHierarchy ) ;
}
2024-05-24 14:33:22 -04:00
}
else
{
2024-05-07 16:54:01 -04:00
# if WITH_METASOUND_DEBUG_ENVIRONMENT
2024-05-24 14:33:22 -04:00
if ( ! bHasLoggedMissingGraphHierarchyWarning )
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Array Random Get: Graph Hierarchy environment variable needed for Same Node or Same Node in Composition shared state id not found (Graph '%s') " ) , * GraphName ) ;
bHasLoggedMissingGraphHierarchyWarning = true ;
2024-05-07 16:54:01 -04:00
}
2024-05-24 14:33:22 -04:00
# endif // WITH_METASOUND_DEBUG_ENVIRONMENT
2024-05-07 16:54:01 -04:00
}
2023-02-22 18:03:42 -05:00
}
2021-03-15 14:00:26 -04:00
void Execute ( )
{
TriggerOnNext - > AdvanceBlock ( ) ;
TriggerOnReset - > AdvanceBlock ( ) ;
2021-03-29 23:58:06 -04:00
const ArrayType & InputArrayRef = * InputArray ;
2024-02-08 19:58:20 -05:00
if ( InputArrayRef . Num ( ) = = 0 )
2021-04-07 03:05:51 -04:00
{
2023-04-17 15:20:55 -04:00
# if WITH_METASOUND_DEBUG_ENVIRONMENT
2021-04-07 03:05:51 -04:00
if ( ! bHasLoggedEmptyArrayWarning )
{
2021-08-09 15:13:40 -04:00
UE_LOG ( LogMetaSound , Verbose , TEXT ( " Array Random Get: empty array input (Graph '%s') " ) , * GraphName ) ;
2021-04-07 03:05:51 -04:00
bHasLoggedEmptyArrayWarning = true ;
}
2023-04-17 15:20:55 -04:00
# endif // WITH_METASOUND_DEBUG_ENVIRONMENT
2024-05-24 14:33:22 -04:00
// Pass through triggers
TriggerReset - > ExecuteBlock (
[ & ] ( int32 StartFrame , int32 EndFrame )
{
} ,
[ this ] ( int32 StartFrame , int32 EndFrame )
{
TriggerOnReset - > TriggerFrame ( StartFrame ) ;
}
) ;
TriggerNext - > ExecuteBlock (
[ & ] ( int32 StartFrame , int32 EndFrame )
{
} ,
[ this ] ( int32 StartFrame , int32 EndFrame )
{
TriggerOnNext - > TriggerFrame ( StartFrame ) ;
}
) ;
2021-04-07 03:05:51 -04:00
return ;
}
2024-05-07 16:54:01 -04:00
2021-03-15 14:00:26 -04:00
TriggerReset - > ExecuteBlock (
[ & ] ( int32 StartFrame , int32 EndFrame )
{
} ,
[ this ] ( int32 StartFrame , int32 EndFrame )
{
2024-05-07 16:54:01 -04:00
ExecuteTriggerReset ( StartFrame ) ;
2021-03-15 14:00:26 -04:00
}
) ;
TriggerNext - > ExecuteBlock (
[ & ] ( int32 StartFrame , int32 EndFrame )
{
} ,
[ this ] ( int32 StartFrame , int32 EndFrame )
{
2024-02-08 19:58:20 -05:00
ExecuteTriggerNext ( StartFrame ) ;
2021-03-15 14:00:26 -04:00
}
) ;
}
private :
2024-05-07 16:54:01 -04:00
void CreateSharedStateArgs ( InitSharedStateArgs & InOutStateArgs )
{
InOutStateArgs . SharedStateId = SharedStateId ;
InOutStateArgs . Seed = * SeedValue ;
InOutStateArgs . NumElements = ( * InputArray ) . Num ( ) ;
InOutStateArgs . NoRepeatOrder = * NoRepeatOrder ;
InOutStateArgs . bIsPreviewSound = bIsPreviewSound ;
InOutStateArgs . Weights = * InputWeightsArray ;
}
void ExecuteTriggerReset ( int32 StartFrame )
{
const ArrayType & InputArrayRef = * InputArray ;
if ( * bEnableSharedState & & ! bIsPreviewSound )
{
// Update shared state id for array content hash
if ( SharedStateBehavior = = ESharedStateBehaviorType : : SameData )
{
SharedStateId = MetasoundArrayHashPrivate : : GetArrayContentHashGuid ( * InputArray ) ;
}
FSharedStateRandomGetManager & RGM = FSharedStateRandomGetManager : : Get ( ) ;
InitSharedStateArgs StateArgs ;
CreateSharedStateArgs ( StateArgs ) ;
// Update and reset seed as one operation
RGM . ResetSeed ( SharedStateId , StateArgs ) ;
}
else // No shared state
{
if ( ! ArrayRandomGet . IsValid ( ) )
{
ArrayRandomGet = MakeUnique < FArrayRandomGet > ( * SeedValue , InputArrayRef . Num ( ) , * InputWeightsArray , * NoRepeatOrder ) ;
}
else
{
ArrayRandomGet - > UpdateState ( * SeedValue , InputArrayRef . Num ( ) , * InputWeightsArray , * NoRepeatOrder ) ;
}
ArrayRandomGet - > ResetSeed ( ) ;
}
TriggerOnReset - > TriggerFrame ( StartFrame ) ;
}
2024-02-08 19:58:20 -05:00
void ExecuteTriggerNext ( int32 StartFrame )
{
const ArrayType & InputArrayRef = * InputArray ;
2024-05-07 16:54:01 -04:00
if ( * bEnableSharedState & & ! bIsPreviewSound )
{
// Update shared state id for array content hash
if ( SharedStateBehavior = = ESharedStateBehaviorType : : SameData )
{
SharedStateId = MetasoundArrayHashPrivate : : GetArrayContentHashGuid ( * InputArray ) ;
}
2024-02-08 19:58:20 -05:00
FSharedStateRandomGetManager & RGM = FSharedStateRandomGetManager : : Get ( ) ;
2024-05-07 16:54:01 -04:00
InitSharedStateArgs StateArgs ;
CreateSharedStateArgs ( StateArgs ) ;
// Update and get next value as one operation
* OutIndex = RGM . NextValue ( SharedStateId , StateArgs ) ;
2024-02-08 19:58:20 -05:00
}
2024-05-07 16:54:01 -04:00
else // No shared state
2024-02-08 19:58:20 -05:00
{
2024-05-07 16:54:01 -04:00
// Initialize or update state
if ( ! ArrayRandomGet . IsValid ( ) )
{
ArrayRandomGet = MakeUnique < FArrayRandomGet > ( * SeedValue , InputArrayRef . Num ( ) , * InputWeightsArray , * NoRepeatOrder ) ;
}
else
{
ArrayRandomGet - > UpdateState ( * SeedValue , InputArrayRef . Num ( ) , * InputWeightsArray , * NoRepeatOrder ) ;
}
// Get next value
* OutIndex = ArrayRandomGet - > NextValue ( ) ;
2024-02-08 19:58:20 -05:00
}
2024-05-07 16:54:01 -04:00
check ( * OutIndex ! = INDEX_NONE ) ;
2024-02-08 19:58:20 -05:00
# if WITH_METASOUND_DEBUG_ENVIRONMENT
2024-05-07 16:54:01 -04:00
UE_LOG ( LogMetaSound , VeryVerbose , TEXT ( " Array Random Get Execute Next: \
Index chosen : % u , Graph : ' % s ' , NumRepeats : % d , Array Size : % u , Seed : % d , Type : % s \
Node Id : % s , Shared State Enabled : % u , Shared State Behavior : % s , Shared State Id : % s " ), \
* OutIndex , * GraphName , * NoRepeatOrder , InputArrayRef . Num ( ) , * SeedValue , * Metasound : : GetMetasoundDataTypeString < ElementType > ( ) , \
* NodeId . ToString ( ) , * bEnableSharedState , * DebugSharedStateBehaviorString , * SharedStateId . ToString ( ) ) ;
2024-02-08 19:58:20 -05:00
# endif // WITH_METASOUND_DEBUG_ENVIRONMENT
// The input array size may have changed, so make sure it's wrapped into range of the input array
2024-05-07 16:54:01 -04:00
* OutValue = InputArrayRef [ * OutIndex % InputArrayRef . Num ( ) ] ;
2024-02-08 19:58:20 -05:00
TriggerOnNext - > TriggerFrame ( StartFrame ) ;
}
2024-05-24 14:33:22 -04:00
// Hash combine the current node id with another id
FGuid GetSameNodeSharedStateId ( const FGuid & InNodeId , const FGuid & InOtherId ) const
{
return FGuid (
HashCombineFast ( InNodeId . A , InOtherId . A ) ,
HashCombineFast ( InNodeId . B , InOtherId . B ) ,
HashCombineFast ( InNodeId . C , InOtherId . C ) ,
HashCombineFast ( InNodeId . D , InOtherId . D )
) ;
}
2024-05-07 16:54:01 -04:00
// Hash combine the current node id with the graph hierarchy ids
FGuid GetSameNodeInCompositionId ( const FGuid & InNodeId , const TArray < FGuid > & InGraphHierarchy ) const
2024-02-13 20:28:54 -05:00
{
2024-05-07 16:54:01 -04:00
uint32 A = InNodeId . A ; uint32 B = InNodeId . B ; uint32 C = InNodeId . C ; uint32 D = InNodeId . D ;
for ( int i = 0 ; i < InGraphHierarchy . Num ( ) ; + + i )
2023-04-17 15:20:55 -04:00
{
2024-05-07 16:54:01 -04:00
A = HashCombineFast ( A , InGraphHierarchy [ i ] . A ) ;
B = HashCombineFast ( B , InGraphHierarchy [ i ] . B ) ;
C = HashCombineFast ( C , InGraphHierarchy [ i ] . C ) ;
D = HashCombineFast ( D , InGraphHierarchy [ i ] . D ) ;
2023-04-17 15:20:55 -04:00
}
2024-05-07 16:54:01 -04:00
return FGuid ( A , B , C , D ) ;
2023-04-17 15:20:55 -04:00
}
2024-05-07 16:54:01 -04:00
2021-03-15 14:00:26 -04:00
// Inputs
FTriggerReadRef TriggerNext ;
FTriggerReadRef TriggerReset ;
FArrayDataReadReference InputArray ;
2021-04-03 18:41:39 -04:00
TDataReadReference < WeightsArrayType > InputWeightsArray ;
2021-03-15 14:00:26 -04:00
FInt32ReadRef SeedValue ;
FInt32ReadRef NoRepeatOrder ;
2024-05-07 16:54:01 -04:00
FBoolReadRef bEnableSharedState ;
FEnumSharedStateBehaviorType SharedStateBehavior ;
2021-03-15 14:00:26 -04:00
// Outputs
FTriggerWriteRef TriggerOnNext ;
FTriggerWriteRef TriggerOnReset ;
TDataWriteReference < ElementType > OutValue ;
2024-05-07 16:54:01 -04:00
FInt32WriteRef OutIndex ;
2021-03-15 14:00:26 -04:00
2021-08-09 15:13:40 -04:00
# if WITH_METASOUND_DEBUG_ENVIRONMENT
FString GraphName ;
2023-04-17 15:20:55 -04:00
bool bHasLoggedEmptyArrayWarning = false ;
2024-05-07 16:54:01 -04:00
bool bHasLoggedMissingGraphHierarchyWarning = false ;
FString DebugSharedStateBehaviorString ;
2021-08-09 15:13:40 -04:00
# endif // WITH_METASOUND_DEBUG_ENVIRONMENT
2021-03-15 14:00:26 -04:00
// Data
TUniquePtr < FArrayRandomGet > ArrayRandomGet ;
2024-05-07 16:54:01 -04:00
FGuid NodeId ;
FGuid SharedStateId ;
2021-04-03 18:41:39 -04:00
bool bIsPreviewSound = false ;
2021-03-15 14:00:26 -04:00
} ;
template < typename ArrayType >
class TArrayRandomGetNode : public FNodeFacade
{
public :
TArrayRandomGetNode ( const FNodeInitData & InInitData )
: FNodeFacade ( InInitData . InstanceName , InInitData . InstanceID , TFacadeOperatorClass < TArrayRandomGetOperator < ArrayType > > ( ) )
{
}
virtual ~ TArrayRandomGetNode ( ) = default ;
} ;
}
2021-04-05 20:22:19 -04:00
# undef LOCTEXT_NAMESPACE