// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "MetasoundBuilderInterface.h" #include "MetasoundNode.h" #include "MetasoundNodeInterface.h" #include "MetasoundOperatorInterface.h" #include "MetasoundDataReference.h" #include "MetasoundExecutableOperator.h" #include "MetasoundRouter.h" #include #define LOCTEXT_NAMESPACE "MetasoundFrontend" namespace Metasound { template class TSendNode : public FNode { public: static const FString& GetAddressInputName() { static const FString InputName = TEXT("Address"); return InputName; } static const FString& GetSendInputName() { static const FString& SendInput = GetMetasoundDataTypeString(); 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 FString& InputName = GetSendInputName(); FNodeClassMetadata Info; Info.ClassName = {TEXT("Send"), GetMetasoundDataTypeName(), TEXT("")}; Info.MajorVersion = 1; Info.MinorVersion = 0; Info.DisplayName = FText::Format(LOCTEXT("Metasound_SendNodeDisplayNameFormat", "Send {0}"), FText::FromName(GetMetasoundDataTypeName())); 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 = { "Send", GetMetasoundDataTypeName()}; 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(FDataTransmissionCenter::Get().RegisterNewSender(CachedSendAddress, CachedSenderParams)) { } 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->ChannelName != CachedSendAddress.ChannelName) { ResetSenderAndCleanupChannel(); CachedSendAddress = *SendAddress; Sender = FDataTransmissionCenter::Get().RegisterNewSender(CachedSendAddress, CachedSenderParams); check(Sender.IsValid()); } Sender->Push(*InputData); } private: void ResetSenderAndCleanupChannel() { Sender.Reset(); FDataTransmissionCenter::Get().UnregisterDataChannelIfUnconnected(GetMetasoundDataTypeName(), 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