Dynamic delegate with templated parameter in Blueprints

Im currently writing my own MessageBus and when Subscribing to a message, one can provide a method that is called when such a message is published. The method header is defined by the following delegate:


DECLARE_DYNAMIC_DELEGATE_OneParam(FMessageFunctionDelegate, TScriptInterface<IIAresMessage>, message);

and the subscribe method is


UFUNCTION(BlueprintCallable) void Subscribe(UClass* messageType, const FMessageFunctionDelegate& method) override;

Thing is, now I always have to cast the message object from IIAresMessage to the actual message type I subscribed so I can get the message’s parameters.

If it was C++ only I’d go with templates but I also want to subscribe to messages in blueprints. So when creating a new event and binding it to the delegate parameter of my Subscribe method in Blueprint, the event’s message parameter should automatically become the type of the messageType parameter of the Subscribe method.

Any ideas how to accomplish this? I know many methods do this like “Construct Object from Class” whose return value automatically becomes the type you provided, but how can I do the same?

If you want to “do the same” then you have to create a custom Kismet Node with compiler instructions to cast the result sub category object to the target input messageType pin of your node.

With simple UFunction() flags I don’t think you would be able to do that.
Blueprints have a concept of “wild card” to imitate templates, but they aren’t easy to deal with as well:



UFUNCTION(BlueprintCallable, meta = (CustomStructureParam = "messageType"))
void Subscribe (UProperty* messageType, const FMessageFunctionDelegate& method);


Then you have to use UField type reflection to cast and get value of variable in your code…

Hmm I see. I found some things regarding CustomThunk and CustomStructureParam. Gonna check it out later.
Do you have any pointers regarding the custom kismet node?

I use custom Kismet Node for my object pool plugin to cast result pooled object to user’s target class, also to generate pins user’s class has marked to be “exposed on spawn”.

I read value of sub object from pin to get the target Class*, then from that class I use type reflection to generate class pins and cast the output “result” pin to an instance object of that same target class, instead of returning a generic APooledActor.

They are complicated to understand, but engine have tons of examples in souce, they all begin with “K2Node_” and similar prefix.

Thanks for the help, I’ll give it a shot after work :slight_smile:

Sooo I tinkered a bit around and got a custom K2Node working.
My next step would be to inherit from UK2Node_CustomEvent and parse out the message type I subscribed to. UK2Node_CustomEvent::ReconstructNode() does a lot of this stuff.

Hmm I can’t seem to get my code to compile:


1>BPNode_SubscribeToMessage.cpp.obj : error LNK2001: unresolved external symbol "public: virtual bool __cdecl UK2Node_CustomEvent::IsEditable(void)const " (?IsEditable@UK2Node_CustomEvent@@UEBA_NXZ)
1>BPNode_SubscribeToMessage.gen.cpp.obj : error LNK2001: unresolved external symbol "public: virtual bool __cdecl UK2Node_CustomEvent::IsEditable(void)const " (?IsEditable@UK2Node_CustomEvent@@UEBA_NXZ)
1>BPNode_SubscribeToMessage.cpp.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl UK2Node_CustomEvent::Serialize(class FArchive &)" (?Serialize@UK2Node_CustomEvent@@UEAAXAEAVFArchive@@@Z)
1>BPNode_SubscribeToMessage.gen.cpp.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl UK2Node_CustomEvent::Serialize(class FArchive &)" (?Serialize@UK2Node_CustomEvent@@UEAAXAEAVFArchive@@@Z)
1>BPNode_SubscribeToMessage.cpp.obj : error LNK2019: unresolved external symbol "public: virtual void __cdecl UK2Node_CustomEvent::ReconstructNode(void)" (?ReconstructNode@UK2Node_CustomEvent@@UEAAXXZ) referenced in function "private: virtual void __cdecl UBPNode_SubscribeToMessage::ReconstructNode(void)" (?ReconstructNode@UBPNode_SubscribeToMessage@@EEAAXXZ)
1>BPNode_SubscribeToMessage.cpp.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl UK2Node_CustomEvent::OnRenameNode(class FString const &)" (?OnRenameNode@UK2Node_CustomEvent@@UEAAXAEBVFString@@@Z)
1>BPNode_SubscribeToMessage.gen.cpp.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl UK2Node_CustomEvent::OnRenameNode(class FString const &)" (?OnRenameNode@UK2Node_CustomEvent@@UEAAXAEBVFString@@@Z)
1>BPNode_SubscribeToMessage.cpp.obj : error LNK2001: unresolved external symbol "public: virtual class TSharedPtr<class INameValidatorInterface,0> __cdecl UK2Node_CustomEvent::MakeNameValidator(void)const " (?MakeNameValidator@UK2Node_CustomEvent@@UEBA?AV?$TSharedPtr@VINameValidatorInterface@@$0A@@@XZ)
1>BPNode_SubscribeToMessage.gen.cpp.obj : error LNK2001: unresolved external symbol "public: virtual class TSharedPtr<class INameValidatorInterface,0> __cdecl UK2Node_CustomEvent::MakeNameValidator(void)const " (?MakeNameValidator@UK2Node_CustomEvent@@UEBA?AV?$TSharedPtr@VINameValidatorInterface@@$0A@@@XZ)
1>BPNode_SubscribeToMessage.cpp.obj : error LNK2001: unresolved external symbol "public: virtual class FString __cdecl UK2Node_CustomEvent::GetDocumentationLink(void)const " (?GetDocumentationLink@UK2Node_CustomEvent@@UEBA?AVFString@@XZ)
1>BPNode_SubscribeToMessage.gen.cpp.obj : error LNK2001: unresolved external symbol "public: virtual class FString __cdecl UK2Node_CustomEvent::GetDocumentationLink(void)const " (?GetDocumentationLink@UK2Node_CustomEvent@@UEBA?AVFString@@XZ)
1>BPNode_SubscribeToMessage.cpp.obj : error LNK2001: unresolved external symbol "public: virtual class FString __cdecl UK2Node_CustomEvent::GetDocumentationExcerptName(void)const " (?GetDocumentationExcerptName@UK2Node_CustomEvent@@UEBA?AVFString@@XZ)
1>BPNode_SubscribeToMessage.gen.cpp.obj : error LNK2001: unresolved external symbol "public: virtual class FString __cdecl UK2Node_CustomEvent::GetDocumentationExcerptName(void)const " (?GetDocumentationExcerptName@UK2Node_CustomEvent@@UEBA?AVFString@@XZ)
1>BPNode_SubscribeToMessage.cpp.obj : error LNK2001: unresolved external symbol "public: virtual struct FSlateIcon __cdecl UK2Node_CustomEvent::GetIconAndTint(struct FLinearColor &)const " (?GetIconAndTint@UK2Node_CustomEvent@@UEBA?AUFSlateIcon@@AEAUFLinearColor@@@Z)
1>BPNode_SubscribeToMessage.gen.cpp.obj : error LNK2001: unresolved external symbol "public: virtual struct FSlateIcon __cdecl UK2Node_CustomEvent::GetIconAndTint(struct FLinearColor &)const " (?GetIconAndTint@UK2Node_CustomEvent@@UEBA?AUFSlateIcon@@AEAUFLinearColor@@@Z)
1>BPNode_SubscribeToMessage.cpp.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl UK2Node_CustomEvent::AutowireNewNode(class UEdGraphPin *)" (?AutowireNewNode@UK2Node_CustomEvent@@UEAAXPEAVUEdGraphPin@@@Z)
1>BPNode_SubscribeToMessage.gen.cpp.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl UK2Node_CustomEvent::AutowireNewNode(class UEdGraphPin *)" (?AutowireNewNode@UK2Node_CustomEvent@@UEAAXPEAVUEdGraphPin@@@Z)
1>BPNode_SubscribeToMessage.cpp.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl UK2Node_CustomEvent::AddSearchMetaDataInfo(class TArray<struct FSearchTagDataPair,class FDefaultAllocator> &)const " (?AddSearchMetaDataInfo@UK2Node_CustomEvent@@UEBAXAEAV?$TArray@UFSearchTagDataPair@@VFDefaultAllocator@@@@@Z)
1>BPNode_SubscribeToMessage.gen.cpp.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl UK2Node_CustomEvent::AddSearchMetaDataInfo(class TArray<struct FSearchTagDataPair,class FDefaultAllocator> &)const " (?AddSearchMetaDataInfo@UK2Node_CustomEvent@@UEBAXAEAV?$TArray@UFSearchTagDataPair@@VFDefaultAllocator@@@@@Z)
1>BPNode_SubscribeToMessage.cpp.obj : error LNK2001: unresolved external symbol "public: virtual class FText __cdecl UK2Node_CustomEvent::GetKeywords(void)const " (?GetKeywords@UK2Node_CustomEvent@@UEBA?AVFText@@XZ)
1>BPNode_SubscribeToMessage.gen.cpp.obj : error LNK2001: unresolved external symbol "public: virtual class FText __cdecl UK2Node_CustomEvent::GetKeywords(void)const " (?GetKeywords@UK2Node_CustomEvent@@UEBA?AVFText@@XZ)
1>BPNode_SubscribeToMessage.cpp.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl UK2Node_CustomEvent::GetMenuActions(class FBlueprintActionDatabaseRegistrar &)const " (?GetMenuActions@UK2Node_CustomEvent@@UEBAXAEAVFBlueprintActionDatabaseRegistrar@@@Z)
1>BPNode_SubscribeToMessage.gen.cpp.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl UK2Node_CustomEvent::GetMenuActions(class FBlueprintActionDatabaseRegistrar &)const " (?GetMenuActions@UK2Node_CustomEvent@@UEBAXAEAVFBlueprintActionDatabaseRegistrar@@@Z)
1>BPNode_SubscribeToMessage.cpp.obj : error LNK2001: unresolved external symbol "public: virtual class UEdGraphPin * __cdecl UK2Node_CustomEvent::CreatePinFromUserDefinition(class TSharedPtr<struct FUserPinInfo,0>)" (?CreatePinFromUserDefinition@UK2Node_CustomEvent@@UEAAPEAVUEdGraphPin@@V?$TSharedPtr@UFUserPinInfo@@$0A@@@@Z)
1>BPNode_SubscribeToMessage.gen.cpp.obj : error LNK2001: unresolved external symbol "public: virtual class UEdGraphPin * __cdecl UK2Node_CustomEvent::CreatePinFromUserDefinition(class TSharedPtr<struct FUserPinInfo,0>)" (?CreatePinFromUserDefinition@UK2Node_CustomEvent@@UEAAPEAVUEdGraphPin@@V?$TSharedPtr@UFUserPinInfo@@$0A@@@@Z)
1>BPNode_SubscribeToMessage.cpp.obj : error LNK2001: unresolved external symbol "public: virtual bool __cdecl UK2Node_CustomEvent::CanCreateUserDefinedPin(struct FEdGraphPinType const &,enum EEdGraphPinDirection,class FText &)" (?CanCreateUserDefinedPin@UK2Node_CustomEvent@@UEAA_NAEBUFEdGraphPinType@@W4EEdGraphPinDirection@@AEAVFText@@@Z)
1>BPNode_SubscribeToMessage.gen.cpp.obj : error LNK2001: unresolved external symbol "public: virtual bool __cdecl UK2Node_CustomEvent::CanCreateUserDefinedPin(struct FEdGraphPinType const &,enum EEdGraphPinDirection,class FText &)" (?CanCreateUserDefinedPin@UK2Node_CustomEvent@@UEAA_NAEBUFEdGraphPinType@@W4EEdGraphPinDirection@@AEAVFText@@@Z)
1>BPNode_SubscribeToMessage.cpp.obj : error LNK2001: unresolved external symbol "public: virtual bool __cdecl UK2Node_CustomEvent::ModifyUserDefinedPinDefaultValue(class TSharedPtr<struct FUserPinInfo,0>,class FString const &)" (?ModifyUserDefinedPinDefaultValue@UK2Node_CustomEvent@@UEAA_NV?$TSharedPtr@UFUserPinInfo@@$0A@@@AEBVFString@@@Z)
1>BPNode_SubscribeToMessage.gen.cpp.obj : error LNK2001: unresolved external symbol "public: virtual bool __cdecl UK2Node_CustomEvent::ModifyUserDefinedPinDefaultValue(class TSharedPtr<struct FUserPinInfo,0>,class FString const &)" (?ModifyUserDefinedPinDefaultValue@UK2Node_CustomEvent@@UEAA_NV?$TSharedPtr@UFUserPinInfo@@$0A@@@AEBVFString@@@Z)
1>BPNode_SubscribeToMessage.cpp.obj : error LNK2001: unresolved external symbol "public: virtual bool __cdecl UK2Node_CustomEvent::IsUsedByAuthorityOnlyDelegate(void)const " (?IsUsedByAuthorityOnlyDelegate@UK2Node_CustomEvent@@UEBA_NXZ)
1>BPNode_SubscribeToMessage.gen.cpp.obj : error LNK2001: unresolved external symbol "public: virtual bool __cdecl UK2Node_CustomEvent::IsUsedByAuthorityOnlyDelegate(void)const " (?IsUsedByAuthorityOnlyDelegate@UK2Node_CustomEvent@@UEBA_NXZ)

BPNode_SubscribeToMessage.h:


#pragma once

#include "CoreMinimal.h"
#include "K2Node_CustomEvent.h"
#include "BPNode_SubscribeToMessage.generated.h"

/**
 *
 */
UCLASS()
class ARESEDITOR_API UBPNode_SubscribeToMessage : public UK2Node_CustomEvent
{
    GENERATED_BODY()

        //~ Begin UEdGraphNode Interface
    virtual FText GetTooltipText() const override;
    virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override;
    //~ End UEdGraphNode Interface

    //~ Begin UK2Node Interface
    virtual void ReconstructNode() override;
};



BPNode_SubscribeToMessage.cpp:


#include "BPNode_SubscribeToMessage.h"
#include "K2Node_CustomEvent.h"
#include "Engine/BlueprintGeneratedClass.h"
#include "EdGraphSchema_K2.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "Kismet2/CompilerResultsLog.h"
#include "BlueprintEventNodeSpawner.h"

#define LOCTEXT_NAMESPACE "UBPNode_OnMessageReceivedEvent"


FText UBPNode_SubscribeToMessage::GetTooltipText() const
{
    return LOCTEXT("OnMessageReceivedEventTooltip", "Test and Test");
}

FText UBPNode_SubscribeToMessage::GetNodeTitle(ENodeTitleType::Type TitleType) const
{
    return LOCTEXT("OnMessageReceivedEvent", "Test");
}

void UBPNode_SubscribeToMessage::ReconstructNode()
{
    Super::ReconstructNode();
    const UEdGraphPin* DelegateOutPin = FindPin(DelegateOutputName);
    const UEdGraphPin* LinkedPin = (DelegateOutPin && DelegateOutPin->LinkedTo.Num() && DelegateOutPin->LinkedTo[0]) ? FBlueprintEditorUtils::FindFirstCompilerRelevantLinkedPin(DelegateOutPin->LinkedTo[0]) : nullptr;

    const UFunction* DelegateSignature = nullptr;

    if (LinkedPin)
    {
        if (const UEdGraphNode* OtherNode = LinkedPin->GetOwningNode())
        {
            bool test = OtherNode->CanJumpToDefinition();
            //DelegateSignature = OtherNode->GetDelegateSignature();
        }
    }
}


#undef LOCTEXT_NAMESPACE



Build.cs:


        PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
        PublicDependencyModuleNames.AddRange(new string] { "Core", "Engine", "CoreUObject", "UnrealEd", "BlueprintGraph" });
        PublicDependencyModuleNames.AddRange(new string] { "Ares" });

        PrivateDependencyModuleNames.AddRange(new string] { "Core", "Engine", "CoreUObject", "UnrealEd", "BlueprintGraph" });

Kismet nodes should be placed into a “Developer” module which the engine will then build for both Editor and dev packages, but it will always fail to build if you try to include any K2Node classes in any runtime modules.

The class already resides in an editor module, therefore inheriting from UK2Node worked. The moment I inherit from UK2Node_CustomEvent though I get these compile errors :confused:

If the class is marked “MinimalAPI” you cannot inherit that class, I’m not sure if that’s the case tho.

Awww shucks it is indeed marked as MinimalAPI :S

Seems like I have to clone the class completely instead of inheriting…