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)?