How to Find non native Functions and Event Dispatchers (BP Delegates) from C++?

Alright so incase anyone else stumbles upon this posting. I want to point out a couple things.

Now with that said, the above is focused on a programmer authored solution. Which wasn’t my personal goal, mine was more oriented towards allowing content creators OR programmers to setup their OWN delegates/event dispatchers and removing the “middle man” scripting between actors and objects in the world.

What I landed on was something I’m happy with. I can’t post the solution but what I will say is the following things were useful:

The following code lets you parse through functions by comparing it with a provided UFunction

TArray<FString> SomeComponent::FindFunctionNamesWithFunctionSignature(AActor* ObjectToLookAt, UFunction* FunctionForSignature)
{

for (TFieldIterator<UFunction> func(ObjectToLookAt->GetClass()); func; ++func) {
	
	if (!func->GetName().Contains(NamingConvention, ESearchCase::IgnoreCase))
	{
		continue;			
	}

	if (!IsValid(FunctionForSignature))
	{
		continue;
	}

//Make sure to add other code here for verification and error checking
	
	ArrayToReturn.Add(func->GetName());
}

The following code can get you all of the Event dispatchers or Delegates from a provided class

void SomeComponent::SetEventDispatchersBasedOnParent()
{
	AActor* Parent = GetOwner();

	if (!IsValid(Parent))
	{
		return;
	}

	for (TFieldIterator<FMulticastDelegateProperty> func(Parent->GetClass()); func; ++func) {

		if (!func->GetName().Contains(NamingConvention, ESearchCase::IgnoreCase))
		{
			continue;
		}

		EventDispatcherToFunctionMap.FindOrAdd(*func->GetName());
	}
}

Now that you have a list of functions from some object, and a list of event dispatchers/ delegates from another, you can tie them together by doing something like this (This is pseudocode):

//To get a FMulticastScriptDelegate

for (TFieldIterator<FMulticastDelegateProperty> CurrentDelegateProperty(Parent->GetClass()); CurrentDelegateProperty; ++CurrentDelegateProperty) {

//This line grabs the actual value of a delegate property.
FMulticastScriptDelegate* CurrentScriptDelegate = CurrentDelegateProperty->ContainerPtrToValuePtr<FMulticastScriptDelegate>(Parent);

//This line grabs a function by name
UFunction* CurrentFunction = CurrentActorKey->FindFunction(*FunctionsToCallPair.Key);

//Once the above is done youll want to do some comparisons and make sure the two are compatible otherwise you could crash your game

//finally bind the two together

DelegateToAddToParentActor.BindUFunction(CurrentActor, FName(FunctionsToCallPair.Key));
CurrentScriptDelegate->Add(DelegateToAddToParentActor);

}

Anyway sorry about the vagueness, but those are all functions that essentially already available through Unreal and I thought I just share my findings and what was useful for me.

One last note, this line is very helpful when trying to compare and validate UFunctions that have the same signature (more pseudocode):

//Collect Properties from UFunctions
TArray<FProperty*> DelegateParams;
for (TFieldIterator<FProperty> It(DelegateFunction); It; ++It)
{
	if ((It->PropertyFlags & CPF_Parm) && !(It->PropertyFlags & CPF_OutParm))
	{
		DelegateParams.Add(*It);
	}
}

TArray<FProperty*> FunctionParams;
for (TFieldIterator<FProperty> It(FirstFunction); It; ++It)
{
	if (It->PropertyFlags & CPF_OutParm)
	{
            return false;
        }

	if ((It->PropertyFlags & CPF_Parm) && !(It->PropertyFlags & CPF_OutParm))
	{
		FunctionParams.Add(*It);
	}
}

//Make sure your parameters are matching between functions and delegates

FStructUtils::ArePropertiesTheSame(CurrentParam, CurrentDelegateParam, false)

Anyway, those are my findings and the pieces that need to be put together, apologies if someone out there wanted actual code. I cannot provide that but all of those functions above would have helped me get to a solution :slight_smile:

1 Like