Call Function By Name --> HERE IS IT! :) <--

	UFUNCTION(BlueprintCallable,meta = (DefaultToSelf = "Object"))
	static bool CallFunctionByName(UObject* Object, FName FunctionName)
	{
		if (Object)
		{
			if (UFunction* Function = Object->FindFunction(FunctionName))
			{
				Object->ProcessEvent(Function, nullptr); return true;
			} return false;
		} return false;
	}

You’re welcome :slight_smile:

2 Likes

my use case:

might be cleaner to use an interface to call it and then switch on name

do you have any example?

You don’t need any switch but you do need an interface.

#pragma once

#include "CoreMinimal.h"
#include "UObject/Interface.h"

#include "HitInterface.generated.h"


UINTERFACE(NotBlueprintable)
class UHitInterface : public UInterface {
    GENERATED_BODY()
};

class IHitInterface {    
    GENERATED_BODY()

public:

    UFUNCTION(BlueprintCallable, BlueprintPure = false)
        virtual void OnHit() = 0;


};
#pragma once

#include "CoreMinimal.h"

#include "MyCar.generated.h"


UCLASS()
class UMyCar : public UObject, public IHitInterface {
	GENERATED_BODY()

public:

	virtual void OnHit() override;

};

This ensures the implementation of what happens on “hit” is written in the classes themselves, not switched on some kind of manager. Whenever you feel like you need a switch or casts (if many) you want to move logic into separate classes, or component. Components can have interfaces too. Then you’d get the component by class (no need for any tags as well), call the interface on it.

1 Like

thats call function by hit, if you want call function by name as the title suggest you need a switch :slight_smile:

1 Like

Yes I did assume this is more logical based on what I see on the use case image.

*Edit * If you do go the “call by name” route, then →

There are downsides to calling a function name by FName. If you were to change your function name at any point any stored function FName will not change and will not notify you that they will not work anymore.

In C++ I can give an example how to pass around UFunction a safe way, that if the name were changed the code would not compile:

template<typename UserClass>
void __Internal_DoStuff(UserClass* InObject, typename TMemFunPtrType<false, UserClass, void()>::Type InFunc, const FName& InFuncName) {
...........
}

#define DoStuff(InObject, InFunc) __Internal_DoStuff(InObject, InFunc, STATIC_FUNCTION_FNAME(TEXT(#InFunc)))

Usage:

DoStuff(this, &AMyActor::MyUFunction);

It’s quite critical to get such functionality right, wouldn’t try to do this in blueprints in the first place, risking FNames going outdated just anywhere.

3 Likes

yeah the base idea is the generic access of functions by name :slight_smile:

I’m mostly seeing cons especially on the blueprint side, and especially if you store the function names up front.

  • blueprint nodes, compiling, etc won’t notify when FNames don’t match a function name.
  • chance of typing mistakes, outdated data, clearing data without notifications.
  • redirectors will not work.

Not seeing the pros yet :smile: my example where I pass along a function pointer was for a specific use case where I want to bind a function on a delegate along with other data.

1 Like

well i use gameplay tags instead of names which fixes some of that, but also the switch node has a default for fail checking

UFUNCTION(BlueprintCallable,meta = (DefaultToSelf = "Object"))
	static bool CallFunctionByName(UObject* Object, FName FunctionName)
	{
		if (Object)
		{
			if (UFunction* Function = Object->FindFunction(FunctionName))
			{
				Object->ProcessEvent(Function, nullptr); return true;
			}
			else
			{
				UE_LOG(LogTemp,Warning,TEXT("Trying to run function named %s but is not found"), *FunctionName.ToString() );
				return false;
			}

		} return false;
	}

now it notifies if function is not found :slight_smile: also the node returns a success bool

I know a lot of people dont recommend using BP nodes like ‘set timer by function name’ as it is error prone and this call function by name can be too but idk…I like it and who doesnt just dont use. Its just a feature.