Can you bind a reflected UFunction* to a FMulticastScriptDelegate* without the concrete delegate type?

I’m working on a custom asset editor, which contains many instances of the following UObject type (or types similar to it).

UCLASS(BlueprintType)
class BOBCAT_API UCustomA : public UObject
{
	GENERATED_BODY()

public:
	DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FCustomA1Delegate, FContext1, Context);
	DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FCustomA2Delegate, FContext2, Context);
	
	UPROPERTY()
	FCustomA1Delegate EventWithContext1;

	UPROPERTY())
	FCustomA2Delegate EventWithContext2;

};

For each custom asset instance (essentially fancy data assets), there is a blueprint related to it (not unlike levels and level blueprints in terms of their 1:1 relationship).
Users can create custom events in the blueprint, which should be automatically bound to the related event during editor-time. Below is a sample chunk of the procedure to gather the relevant pointers to bind the event.

Note: Please bear with the obfuscasion of specifics and code mistakes, this is an uncompiled example / pseudo-code based on what I already have compiling.

UClass* BlueprintGeneratedClass = SomeOtherObjectType->GetClass();
UBlueprint* Blueprint = Cast<UBlueprint>(BlueprintGeneratedClass->ClassGeneratedBy);
UCustomA* OutInstance = NewObject(...);

for (TFieldIterator<FMulticastDelegateProperty> PropertyIt(OutInstwnce->GetClass(), EFieldIteratorFlags::IncludeSuper); PropertyIt; ++PropertyIt)
{
	FMulticastDelegateProperty* Property = *PropertyIt;
    
	/* Specific node in `Blueprint` which is the one and only event generated to handle the Property. Blackbox omitted, but it uses `FBlueprintEditorUtils::GetAllNodesOfClass` on the blueprint with some extra criteria. */
	const UK2Node_Event* GeneratedEventNode = FindBlueprintEventForDelegate(Blueprint, OutInstance, Property);
	UFunction* GeneratedEvent = BlueprintGeneratedClass->FindFunctionByName(GeneratedEventNode->GetFunctionName());
	if (!Property->SignatureFunction->IsSignatureCompatibleWith(GeneratedEvent)) continue;

	FMulticastScriptDelegate* Delegate = Property->ContainerPtrToValuePtr<FMulticastScriptDelegate>(OutInstance);

	/* TODO: Run binding logic here to attach `GeneratedEvent` as a handler when `Delegate` is broadcast. */
}

So my problem/question is how would one bind a generic UFunction* on a specific Blueprint object (i.e. the ClassDefaultObject of a blueprint class) to a generic delegate on a known UObject (non-blueprint)?

All of the normal binding methods are staticly typed (for reasonable and good type safety reasons). In this case, however, I don’t know of a way to get those hard-types when iterating over the reflected property fields (they are often different delegate types). And the only binding method in the currently used types is FMulticastScriptDelegate::Add[Dynamic], which requires some subclass of FScriptDelegate.

Is there some type I can cast one or both of these sides to in order to generate the safely typed structure for binding? If not, are there any recommendations to how one could bind a blueprint-generated function to a delegate, when I only really know the name of both (i.e. the name of the delegate UProperty and the name of the generated function)?

Oh I feel silly. FScriptDelegate has a default constructor, and a method from which you can bind a UObject function by its name.

FScriptDelegate Callback;
Callback.BindUFunction(SomeOtherObjectType, GeneratedEvent->GetFName());
Delegate->AddUnique(Callback);

That properly updates the invocation list on the UCustomA instance (via the delegate pointer).

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.