How to setup Dynamic Single Delegate (with RetVal) to make it bindable from Blueprints?

TL;DR - How shall I create the Dynamic Single Delegate (with Return Value) within C++ in the way that will make this delegate possible to bind from Blueprints?


Context:

I wanted to override some of Component’s functionality within its owning Actor.
I’m already using Dynamic Multicast Sparse Delegates to extend Component’s functionality, so I thought that there should be a similiar Delegate type that would do a job.

After reading more about Delegates, I realized that Dynamic Single Delegate with Return Value is probably what I’m looking for.
According to the linked article and to the source, these are indeed Blueprint friendly.

Advanced Delegates in C++ · ben🌱ui :

DelegateCombinations.h (lines 43-44) :

/** Declares a blueprint-accessible delegate with return value that can only bind to one UNFUNCTION at a time */
#define DECLARE_DYNAMIC_DELEGATE_RetVal( ReturnValueType, DelegateName ) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_DELEGATE) FUNC_DECLARE_DYNAMIC_DELEGATE_RETVAL( FWeakObjectPtr, DelegateName, DelegateName##_DelegateWrapper, ReturnValueType, , FUNC_CONCAT( *this ), ReturnValueType )

My problem:

I just don’t know how to set this thing up in the right way. I’m not sure which UPROPERTY Specifiers shall I use for delegate property. I tried multiple things, and they don’t really work.


What I’ve tried:

  1. Making delegate’s property “BlueprintAssignable”.
    Sadly, this is only allowed for Multicast Delegates.
// this is inside class declaration:
public:
	DECLARE_DYNAMIC_DELEGATE_RetVal_OneParam(bool, FTestDelegate, bool, Param)
	UPROPERTY(BlueprintAssignable)
	FTestDelegate TestDelegate;

image

  1. Making delegate’s property “EditAnywhere” or “EditDefaultsOnly”.
    This doesn’t seem to be supported. In this case, Delegate variable is just disabled in Details panel.
UPROPERTY(EditAnywhere)
FTestDelegate TestDelegate;

image

  1. Making delegate’s property “BlueprintReadOnly” or “BlueprintReadWrite”.
    This kidna seems to work. But this approach is very ugly. It’s hard to belive that delegates would be used in such way. This would also ment that assigned function won’t be known untill BeginPlay runs (which is big NO NO for me)
UPROPERTY(BlueprintReadWrite)
FTestDelegate TestDelegate;

image


I’ll be really thankful for any kind of guidence :slight_smile:

After googling a litle bit more, looks like this is the correct aproach, which worries me A LOT.

Is there a way to somehow store the reference to UFunction on the Blueprint side, so I could somehow set it from Details Panel?

I would like to avoid ugly boilerplate…

3 Likes

Thank you for posting this and your solution, seems hard to find any other options.

1 Like

Option #3 still doesn’t solve this problem but I have few notes:

  • Construction Script can be used instead of BeginPlay (not sure how I missed it in the first place)
  • This might be possible to solve with Interface and I’m also pretty sure that I’ve seen something similar in Unreal’s GAS

Hi there!

I was messing around with this too and thought id throw some more notes out there :slight_smile:

its also possible to bind these delegates like so (which looks less ugly imo):

Declaration.h

DECLARE_DYNAMIC_DELEGATE_OneParam(FMyDynamicDelegate, uint32, SomeVar);

UCLASS(Blueprintable)
class PROJECT_API USomeObject : public UObject
{
  GENERATED_BODY()

public:
  FMyDynamicDelegate DynamicDelegate;
}

Implementation.cpp

void USomeObject::BindSomeFunc(FMyDynamicDelegate NewDynamicDelegate)
{
  DynamicDelegate = NewDynamicDelegate;
}
	

and this would essentially provide you with the same function to bind an event like you would to an event dispatcher in BP

1 Like

Hey @andkiller,

This would indeed avoid the need of using property specifiers on the Delegate itself.

However, if I understand right, the outcome is pretty much the same. You’re just providing your very own setter function, same as the one that would be generated automatically. Also, after all you gotta use a specifier on the BindSomeFunc, if you want to make it accessible from Blueprints.

Not a big fan of this solution, unless I’m missing something here. Please, tell me, if I do!

Thanks thought, it’s still a valid alternative.