// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "MetasoundBuilderInterface.h" #include "MetasoundNode.h" #include "MetasoundNodeInterface.h" #include "MetasoundOperatorInterface.h" #include "MetasoundDataReference.h" #include "MetasoundExecutableOperator.h" #include "MetasoundRouter.h" #include "MetasoundVertex.h" #include #define LOCTEXT_NAMESPACE "MetasoundFrontend" namespace Metasound { template class TSendNode : public FNode { public: static const FVertexName& GetAddressInputName() { static const FVertexName InputName = TEXT("Address"); return InputName; } static const FVertexName& GetSendInputName() { static const FVertexName& SendInput = GetMetasoundDataTypeName(); return SendInput; } static FVertexInterface DeclareVertexInterface() { return FVertexInterface( FInputVertexInterface( TInputDataVertexModel(GetAddressInputName(), FText::GetEmpty()), TInputDataVertexModel(GetSendInputName(), FText::GetEmpty()) ), FOutputVertexInterface( ) ); } static const FNodeClassMetadata& GetNodeInfo() { auto InitNodeInfo = []() -> FNodeClassMetadata { const FVertexName& InputName = GetSendInputName(); FNodeClassMetadata Info; Info.ClassName = { "Send", GetMetasoundDataTypeName(), FName() }; Info.MajorVersion = 1; Info.MinorVersion = 0; Info.DisplayName = FText::Format(LOCTEXT("Metasound_SendNodeDisplayNameFormat", "Send {0}"), GetMetasoundDataTypeDisplayText()); Info.Description = LOCTEXT("Metasound_SendNodeDescription", "Sends 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 TSendOperator : public TExecutableOperator { public: TSendOperator(TDataReadReference InInputData, TDataReadReference InSendAddress, const FOperatorSettings& InOperatorSettings) : InputData(InInputData) , SendAddress(InSendAddress) , CachedSendAddress(*InSendAddress) , CachedSenderParams({InOperatorSettings, 0.0f}) , Sender(nullptr) { Sender = CreateNewSender(); } virtual ~TSendOperator() { ResetSenderAndCleanupChannel(); } virtual FDataReferenceCollection GetInputs() const override { FDataReferenceCollection Inputs; Inputs.AddDataReadReference(GetAddressInputName(), SendAddress); Inputs.AddDataReadReference(GetSendInputName(), TDataReadReference(InputData)); return Inputs; } virtual FDataReferenceCollection GetOutputs() const override { return {}; } void Execute() { if (*SendAddress != CachedSendAddress) { ResetSenderAndCleanupChannel(); CachedSendAddress = *SendAddress; Sender = CreateNewSender(); check(Sender.IsValid()); } Sender->Push(*InputData); } private: TSenderPtr CreateNewSender() const { if (ensure(SendAddress->GetDataType().IsNone() || (GetMetasoundDataTypeName() == SendAddress->GetDataType()))) { FSendAddress DataChannelKey(SendAddress->GetChannelName(), GetMetasoundDataTypeName(), SendAddress->GetInstanceID()); return FDataTransmissionCenter::Get().RegisterNewSender(DataChannelKey, CachedSenderParams); } return TSenderPtr(nullptr); } void ResetSenderAndCleanupChannel() { Sender.Reset(); FDataTransmissionCenter::Get().UnregisterDataChannelIfUnconnected(CachedSendAddress); } TDataReadReference InputData; TDataReadReference SendAddress; FSendAddress CachedSendAddress; FSenderInitParams CachedSenderParams; TSenderPtr Sender; }; class FSendOperatorFactory : public IOperatorFactory { public: FSendOperatorFactory() = default; virtual TUniquePtr CreateOperator(const FCreateOperatorParams& InParams, FBuildErrorArray& OutErrors) override { if (InParams.InputDataReferences.ContainsDataReadReference(GetSendInputName())) { return MakeUnique(InParams.InputDataReferences.GetDataReadReference(GetSendInputName()), InParams.InputDataReferences.GetDataReadReferenceOrConstruct(GetAddressInputName()), InParams.OperatorSettings ); } else { // No input hook up to send, so this node can no-op return MakeUnique(); } } }; public: TSendNode(const FNodeInitData& InInitData) : FNode(InInitData.InstanceName, InInitData.InstanceID, GetNodeInfo()) , Interface(DeclareVertexInterface()) , Factory(MakeOperatorFactoryRef()) { } virtual ~TSendNode() = 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