Binding a multicast dynamic delegate via BlueprintNativeEvent from a blueprintable native interface?

I am making an interface, blueprintable with BlueprintNativeEvent methods. For most purposes this has worked just fine, but I have run into a problem with exposing all the functionality I want via these interfaces. As is standard, some of the important methods have an On_______ event that allows the class to handle something, and a multicast delegate for level blueprints and other classes to watch the event that is also broadcast by the function. The first part is simple, but how can I support the multicast delegate?

I have done some searching and have seen some alternative solutions like a c++ only way to bind via interface, and a reflection based one that takes the FName of a function and the caller. Link: https://www.reddit.com/r/unrealengine/comments/bczcuv/any_way_to_have_a_delegate_on_a_uinterface/ekwtro2/?context=8&depth=9

I also considered listener interfaces and using that instead of multicast delegates but this is not ideal.

What I want is to basically recreate the Bind K2 node that you can drag the little red box pin out of a custom event into. My search through the engine source for how these nodes function have proven fruitless.

Is anyone aware of a way to pass an event handler or blueprint class function in as an argument so i can do the actual binding to that classes version of the delegate within the implementation of the interface function? Or am I better off with the the workaround from that Reddit thread I linked, where the interface can bind using the function name? I really do not want to work against the blueprint visual script standards.

Hello! Just use BlueprintAssignable specifier with your delegate UProperty, like this:

UPROPERTY(BlueprintAssignable, Category="Collision")
	FComponentBeginOverlapSignature OnComponentBeginOverlap;

Unfortunately, this method is unavailable to me in this case.

I am making an interface, like this Interfaces | Unreal Engine Documentation

C++ Interfaces only have c++ functions. Adding a member variable, let alone a UProperty results in this compile error:

2>C:/Users/User/Documents/Unreal Projects/ThingYeeter/Plugins/RTSDK/Source/RTSDK/Public/Units/RTSUnitInterface.h(132): error : ‘Member variable declaration’ is not allowed here.

The reason I am doing this is to make it so any actor derived class can become a ‘unit’ as far as the framework is concerned. Each class that can be a unit then implements the functionality in its specific way internally, things communicating with the unit only know their actor typed pointer and that they implement this interface, they do not know the class unless it finds it via reflection. My framework cannot possibly know the classes being used by game modules that use it, as it is part of a plugin intended for multiple projects.

What I am after is a way to expose just the binding and unbinding of the delegate via this interface, allowing classes that are communicating via interface to not know the actual delegate property or the class that is implementing the interface. They would know the signature but they can’t know the property, or at least won’t without reflection. So I either need a way to pass the delegate to the object trying to bind to the delegate via reflection or pass the function being bound to the class that implements the delegate, where the binding is trivial.

Simply passing back the delegate signature property value doesn’t get you there either, the BlueprintAssignable decorator does a lot of heavy lifting to create the bind/unbind/call functionality in blueprint, as the OP of the linked Reddit thread demonstrates.

I do not know what sort of argument a bind/unbind function would take to pass the function/event being bound to the multicast delegate.

I just tried it, unsure how to declare it, pastebin of the interface header

at the top of the file after includes I have
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FRTSTestSignature);

And inside the I class declaration I have
UPROPERTY(BlueprintAssignable, Category = “RTS Unit Interface”)
static FRTSTestSignature ReceiveTestEvent;

But it just results in a compile error telling me variables can’t be part of an interface identical to the one I pasted in the comment above.

Ok, then you can do two things

  • add virtual getter in Interface and override it in every inherited class
  • use common static delegate. Here you will need to pass additional pointer as delegate param to check on what instance was delegate broadcasted…

As for the getter, what would the getter function return in order to have the ability to bind off the return value within a blueprint and c++?

Yeah basically I would vastly prefer the ability to bind to the multicast delegate in both bp and c++, and unbind from it using just the interface.

My current workaround (that I am not entirely happy with) might help get across what I’m trying to accomplish.

Within the interface:

 UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "RTS Unit Interface")
		bool BindToOnUpdateUnitStatReceived(UObject* TargetObject, FName FunctionName);

	UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "RTS Unit Interface")
		bool UnbindToOnUpdateUnitStatReceived(UObject* TargetObject, FName FunctionName);

Implemented by these:

 bool ARTSUnit::BindToOnUpdateUnitStatReceived_Implementation(UObject* TargetObject, FName FunctionName)
 {
	FScriptDelegate d;
	d.BindUFunction(TargetObject, FunctionName);
	OnUpdateUnitStatDelegate.Add(d);
	return d.IsBound();
 }

 bool ARTSUnit::UnbindToOnUpdateUnitStatReceived_Implementation(UObject* TargetObject, FName FunctionName)
 {
	FScriptDelegate d;
	d.BindUFunction(TargetObject, FunctionName);
	
	OnUpdateUnitStatDelegate.Remove(d);
	return true;
 }

Which has the following problems.

  1. Function signature can’t be just copied easily, and I will have to add in additional checks to see if the function can be safely bound, wrong number of params and you get an exception at runtime when the multicast delegate broadcasts that isn’t very indicative of what went wrong.

  2. How would a blueprint override these BindTo and UnbindTo interface methods? I’m using reflection to do it via FName

  3. This isn’t the normal workflow for binding to a multicast event at all, too quirky, more work than otherwise too.

It does at least work, though. Both binding and unbinding.

Is there a better way?

Ok. So you want to have a delegate in Interface to broadcast it from some of interface function and also wanto to subscribe to it from BP and C++. Am I understanding you right?