Download

C++ Interfaces, Pure functions, BP inheritance and all other

Hi all!
I have some thoughts and they relate to interfaces in UE4.

In general, interfaces in UE4 are a pain: I will not show an example, you know what it is about

I would like to have a similar system as in simple C ++ with the ability to be inherited in BP, without stupidly checking the child class on a interface method exist.

This is my changes in the engine:
[SPOILER]
UnrealEngine\Engine\Source\Editor\BlueprintGraph\Classes\EdGraphSchema_K2.h



229 /** Allow Custom override*/
230 static const FName MD_AllowOverride;
...
800 /** Can this function may be custom override */
801 static bool FunctionAllowOverride(const UFunction* InFunction);


UnrealEngine\Engine\Source\Editor\BlueprintGraph\Private\EdGraphSchema_K2.cpp



187 const FName FBlueprintMetadata::MD_AllowOverride(TEXT("AllowOverride")); 
...
924 bool UEdGraphSchema_K2::FunctionAllowOverride(const UFunction* InFunction)
{
return InFunction && InFunction->GetBoolMetaData(FBlueprintMetadata::MD_AllowOverride);
}

929 bool UEdGraphSchema_K2::CanKismetOverrideFunction(const UFunction* Function)
{
/* return Function && // original code
(
Function->HasAllFunctionFlags(FUNC_BlueprintEvent)
&& !Function->HasAllFunctionFlags(FUNC_Delegate) &&
!Function->GetBoolMetaData(FBlueprintMetadata::MD_BlueprintInternalUseOnly) &&
(!Function->HasMetaData(FBlueprintMetadata::MD_DeprecatedFunction) || GetDefault<UBlueprintEditorSettings>()->bExposeDeprecatedFunctions)
);
*/

const auto IsNotBad = Function && (!Function->HasMetaData(FBlueprintMetadata::MD_DeprecatedFunction) || GetDefault<UBlueprintEditorSettings>()->bExposeDeprecatedFunctions);
const auto IsEvent = Function && Function->HasAllFunctionFlags(FUNC_BlueprintEvent);
const auto IsNotDelegate = Function && !Function->HasAllFunctionFlags(FUNC_Delegate);
const auto IsNotInternal = Function && !Function->GetBoolMetaData(FBlueprintMetadata::MD_BlueprintInternalUseOnly) ;
const auto IsAllowOverride = FunctionAllowOverride(Function);

return IsNotBad && IsNotDelegate && IsNotInternal && ( IsEvent || IsAllowOverride );
}

964 bool UEdGraphSchema_K2::FunctionCanBePlacedAsEvent(const UFunction* InFunction)
{
/*
// First check we are override-able, non-static and non-const
if (!InFunction || !CanKismetOverrideFunction(InFunction) || InFunction->HasAnyFunctionFlags(FUNC_Static|FUNC_Const))
{
return false;
}

// Then look to see if we have any output, return, or reference params
return !HasFunctionAnyOutputParameter(InFunction);
*/
const auto IsOverride = InFunction && CanKismetOverrideFunction(InFunction);
const auto IsStaticConst = InFunction && InFunction->HasAnyFunctionFlags(FUNC_Static|FUNC_Const);
const auto IsEvent = InFunction && InFunction->HasAllFunctionFlags(FUNC_BlueprintEvent);
const auto IsHasOutParams = HasFunctionAnyOutputParameter(InFunction);

if(!IsOverride || IsStaticConst) return false;

return IsEvent && !IsHasOutParams;
}

UnrealEngine\Engine\Source\Editor\KismetCompiler\Private\KismetCompiler.cpp



3258 //const bool bCanBeOverridden = Function->HasAllFunctionFlags(FUNC_BlueprintEvent); // original code
const bool bCanBeOverridden = Function->HasAllFunctionFlags(FUNC_BlueprintEvent) || Function->GetBoolMetaData(FBlueprintMetadata::MD_AllowOverride);
if (!bCanBeOverridden)
{
MessageLog.Error(TEXT("The function in node @@ cannot be overridden"), EntryNode);
}

[/SPOILER]

How to use in project:

[SPOILER]

Interface declaration:

Override in child class:

Select to override in inherited BP.

BP_interface 1.png

Note, void returned methods(Events) is possible override as Functions (I am dnt like Events - theys cluttered graphs)

Used in AnimInstance class( my case):

Declaration var in header:

Used in souce:

[/SPOILER]

This is not ideal case. On example, if use Owner->OnHealthChanged() (last example see upward), overrided function in BP not fired, becouse used class d`nt know about BP function.

Thinking, need dig in BlueprintImplementableEvent and make it same.

I’d love to see interfaces in UE convenient, this is necessary for those who work in C ++.

Thank you for the attention.

The only time you can call an interface function directly:

  • The interface has “CannotImplementInterfaceInBlueprint”
  • You have a pointer to an object whose native class implements the interface.
  • The function is not a UFUNCTION, or is BlueprintCallable ONLY

Even with CPP-only interfaces, if you make that function a BlueprintNativeEvent or a BlueprintImplementableEvent, the code generated by UHT will cause you to instantly crash when calling it directly, especially if you have implemented/overridden the function in a derived Blueprint.

Interface functions almost always have to be called through reflection (via Execute_MyFunction). I made a Pull-Request sometime ago that allows for non-virtual Blueprint Callable functions for nicer design patterns, but it is yet to be accepted:https://github.com/EpicGames/UnrealEngine/pull/6822

Since your interface only has a Blueprint-Callable function and the interface is implemented in code, you shouldn’t have any reason to make modifications. Here’s an example of it working without needing interface casting (this is an actor blueprint, the native class just implements my projects’ Team Interface)

Most of the time I work in C ++, I declare pure virtual function in interface and I want to be able to override the function everywhere in the code and in BP, without castes, having only a link to the interface. Then you not may use virtual function as BlueprintNativeEvent or a BlueprintImplementableEvent.

If you want override, sorry, redefine( becouse not virtual) function, you must declare function as BlueprintNativeEvent, create Function_Implemantation(), then check
ImplementsInterface() or Cast<> and firing Interface::Execute_Function(). Cool.

In my case all is easier. In code all as basic с++ in BP i may override either virtual function, store reference on Interface and use his methods.

Used 3.PNG

Work all fine, but in c++ if i firing interface method, which was overrided in BP, BP`s method not firing. However, i have assumption that can add.

Generally: less casts - more perfomance :wink:

Sorry, English not my native language.

P.S. I’m not saying that my direction is right, I could be wrong. I want convenient work with a wonderful engine. I think together we can resolve all questions.