// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "MetasoundBuilderInterface.h" #include "MetasoundNode.h" #include "MetasoundNodeInterface.h" #include "MetasoundOperatorInterface.h" #include "MetasoundDataFactory.h" #include "MetasoundDataReference.h" #include "MetasoundExecutableOperator.h" #include "MetasoundRouter.h" #include #define LOCTEXT_NAMESPACE "MetasoundFrontend" namespace Metasound { namespace ReceiveNodeInfo { METASOUNDFRONTEND_API const FVertexName& GetAddressInputName(); METASOUNDFRONTEND_API const FVertexName& GetDefaultDataInputName(); METASOUNDFRONTEND_API const FVertexName& GetOutputName(); METASOUNDFRONTEND_API FNodeClassName GetClassNameForDataType(const FName& InDataTypeName); METASOUNDFRONTEND_API int32 GetCurrentMajorVersion(); METASOUNDFRONTEND_API int32 GetCurrentMinorVersion(); }; template class TReceiveNode : public FNode { public: static FVertexInterface DeclareVertexInterface() { return FVertexInterface( FInputVertexInterface( TInputDataVertexModel(ReceiveNodeInfo::GetAddressInputName(), FText::GetEmpty()), TInputDataVertexModel(ReceiveNodeInfo::GetDefaultDataInputName(), FText::GetEmpty()) ), FOutputVertexInterface( TOutputDataVertexModel(ReceiveNodeInfo::GetOutputName(), FText::GetEmpty()) ) ); } static const FNodeClassMetadata& GetNodeInfo() { auto InitNodeInfo = []() -> FNodeClassMetadata { FNodeClassMetadata Info; Info.ClassName = ReceiveNodeInfo::GetClassNameForDataType(GetMetasoundDataTypeName()); Info.MajorVersion = ReceiveNodeInfo::GetCurrentMajorVersion(); Info.MinorVersion = ReceiveNodeInfo::GetCurrentMinorVersion(); Info.DisplayName = FText::Format(LOCTEXT("Metasound_ReceiveNodeDisplayNameFormat", "Receive {0}"), GetMetasoundDataTypeDisplayText()); Info.Description = LOCTEXT("Metasound_ReceiveNodeDescription", "Receives data from a send node with the same name."); Info.Author = PluginAuthor; Info.PromptIfMissing = PluginNodeMissingPrompt; Info.DefaultInterface = DeclareVertexInterface(); Info.CategoryHierarchy = { LOCTEXT("Metasound_TransmissionNodeCategory", "Transmission") }; Info.Keywords = { }; return Info; }; static const FNodeClassMetadata Info = InitNodeInfo(); return Info; } private: class TReceiverOperator : public TExecutableOperator { TReceiverOperator() = delete; public: TReceiverOperator(TDataReadReference InInitDataRef, TDataWriteReference InOutDataRef, TDataReadReference InSendAddress, const FOperatorSettings& InOperatorSettings) : bHasNotReceivedData(true) , DefaultData(InInitDataRef) , OutputData(InOutDataRef) , SendAddress(InSendAddress) , CachedSendAddress(*InSendAddress) , CachedReceiverParams({InOperatorSettings}) , Receiver(nullptr) { Receiver = CreateNewReceiver(); } virtual ~TReceiverOperator() { ResetReceiverAndCleanupChannel(); } virtual FDataReferenceCollection GetInputs() const override { FDataReferenceCollection Inputs; Inputs.AddDataReadReference(ReceiveNodeInfo::GetDefaultDataInputName(), DefaultData); Inputs.AddDataReadReference(ReceiveNodeInfo::GetAddressInputName(), SendAddress); return Inputs; } virtual FDataReferenceCollection GetOutputs() const override { FDataReferenceCollection Outputs; Outputs.AddDataReadReference(ReceiveNodeInfo::GetOutputName(), TDataReadReference(OutputData)); return Outputs; } void Execute() { if (*SendAddress != CachedSendAddress) { ResetReceiverAndCleanupChannel(); CachedSendAddress = *SendAddress; Receiver = CreateNewReceiver(); } bool bHasNewData = false; if (ensure(Receiver.IsValid())) { bHasNewData = Receiver->CanPop(); if (bHasNewData) { Receiver->Pop(*OutputData); bHasNotReceivedData = false; } } if (bHasNotReceivedData) { *OutputData = *DefaultData; bHasNewData = true; } if (TExecutableDataType::bIsExecutable) { TExecutableDataType::ExecuteInline(*OutputData, bHasNewData); } } private: TReceiverPtr CreateNewReceiver() const { if (ensure(SendAddress->GetDataType().IsNone() || (GetMetasoundDataTypeName() == SendAddress->GetDataType()))) { FSendAddress DataChannelKey(SendAddress->GetChannelName(), GetMetasoundDataTypeName(), SendAddress->GetInstanceID()); return FDataTransmissionCenter::Get().RegisterNewReceiver(DataChannelKey, CachedReceiverParams); } return TReceiverPtr(nullptr); } void ResetReceiverAndCleanupChannel() { Receiver.Reset(); FDataTransmissionCenter::Get().UnregisterDataChannelIfUnconnected(CachedSendAddress); } bool bHasNotReceivedData; TDataReadReference DefaultData; TDataWriteReference OutputData; TDataReadReference SendAddress; FSendAddress CachedSendAddress; FReceiverInitParams CachedReceiverParams; TReceiverPtr Receiver; }; class FReceiverOperatorFactory : public IOperatorFactory { public: FReceiverOperatorFactory() = default; virtual TUniquePtr CreateOperator(const FCreateOperatorParams& InParams, FBuildErrorArray& OutErrors) override { TDataReadReference DefaultReadRef = TDataReadReferenceFactory::CreateAny(InParams.OperatorSettings); if (InParams.InputDataReferences.ContainsDataReadReference(ReceiveNodeInfo::GetDefaultDataInputName())) { DefaultReadRef = InParams.InputDataReferences.GetDataReadReference(ReceiveNodeInfo::GetDefaultDataInputName()); } return MakeUnique( DefaultReadRef, TDataWriteReferenceFactory::CreateAny(InParams.OperatorSettings, *DefaultReadRef), InParams.InputDataReferences.GetDataReadReferenceOrConstruct(ReceiveNodeInfo::GetAddressInputName()), InParams.OperatorSettings ); } }; public: TReceiveNode(const FNodeInitData& InInitData) : FNode(InInitData.InstanceName, InInitData.InstanceID, GetNodeInfo()) , Interface(DeclareVertexInterface()) , Factory(MakeOperatorFactoryRef()) { } virtual ~TReceiveNode() = default; virtual const FVertexInterface& GetVertexInterface() const override { return Interface; } virtual bool SetVertexInterface(const FVertexInterface& InInterface) override { return Interface == InInterface; } virtual bool IsVertexInterfaceSupported(const FVertexInterface& InInterface) const override { return Interface == InInterface; } virtual FOperatorFactorySharedRef GetDefaultOperatorFactory() const override { return Factory; } private: FVertexInterface Interface; FOperatorFactorySharedRef Factory; }; } #undef LOCTEXT_NAMESPACE