Whole Tomato Software Forums
Whole Tomato Software Forums
Main Site | Profile | Register | Active Topics | Members | Search | FAQ
User name:
Password:
Save Password
Forgot your password?

 All Forums
 Visual Assist
 Feature Requests
 UE4 Interface Execute Functions
 New Topic  Reply to Topic
 Printer Friendly
Author Previous Topic Topic Next Topic  

MichaelTraega
Senior Member

USA
25 Posts

Posted - Jul 11 2018 :  3:14:06 PM  Show Profile  Reply with Quote
In order to call an interface function on an object that may not inherit from that interface (but implements it in blueprint), you have to write something like
ITestInterface::Execute_TestInterfaceFunction(Actor);
instead of
Cast<ITestInterface>(Actor)->TestInterfaceFunction();

The class is defined:

class ITestInterface
{
	GENERATED_BODY()

public:

	UFUNCTION(BlueprintNativeEvent, Category = "Test Interface")
	void TestInterfaceFunction();
	
};

Visual Assist X does not recognize ITestInterface::Execute_TestInterfaceFunction(UObject*) which is the syntax you should use for calling interfaces that could be interfaced in blueprint. So I'm asking that this function as described be available for auto complete if the function is blueprint ready.

Edited by - MichaelTraega on Jul 11 2018 3:15:47 PM

feline
Whole Tomato Software

United Kingdom
17095 Posts

Posted - Jul 13 2018 :  1:53:39 PM  Show Profile  Reply with Quote
Do you have a link for a couple of simple examples of using Blueprints? I am currently looking through the documentation to learn enough to put together a couple of sensible examples for this.

zen is the art of being at one with the two'ness
Go to Top of Page

MichaelTraega
Senior Member

USA
25 Posts

Posted - Jul 13 2018 :  2:31:21 PM  Show Profile  Reply with Quote
This wiki entry gives an overview: https://wiki.unrealengine.com/Interfaces_in_C%2B%2B

Basically, you may create an interface that can be BlueprintType, meaning it can be used in blueprints (as well as C++). But unlike in C++, use of an interface in blueprint does not make that blueprint castable to that interface like you would do in C++. So an auto-generated Execute_ function allows a C++ class to try and call an interface function on a object it knows nothing about. If the object was just a C++ class, then using Cast would work. But if the object only extended the interface through blueprint (not some C++ base class) then you have to use Execute_.


// TestInterface.h
#pragma once

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

UINTERFACE(MinimalAPI, BlueprintType)
class UTestInterface : public UInterface
{
	GENERATED_BODY()
};

class ITestInterface
{
	GENERATED_BODY()

public:

	UFUNCTION(BlueprintNativeEvent, Category = "Test Interface")
	void TestInterfaceFunction();
	
};

// TestGameMode.h
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "TestGameMode.generated.h"

UCLASS()
class ATestGameMode : public AGameModeBase
{
	GENERATED_BODY()
	
public:

	UFUNCTION(BlueprintCallable, Category = Test)
	void TestInterfaceOnActor(AActor* Actor);
	
};

// TestGameMode.cpp
#include "TestGameMode.h"
#include "TestInterface.h"


void ATestGameMode::TestInterfaceOnActor(AActor* Actor)
{
	// in this example:
	// interface function is called twice for C++ classes that extended the interface, once for blueprint

	if (ITestInterface* iface = Cast<ITestInterface>(Actor)) // iface is null if actor was a blueprint that extended the interface
	{
		iface->TestInterfaceFunction();
	}
	ITestInterface::Execute_TestInterfaceFunction(Actor); // works for both C++ and blueprint classes that extend the interface
}



Then in editor I set the game mode to be TestGameMode. I create an Actor blueprint called TestActor and then in its class settings I give it my TestInterface interface. I right click in the event graph and then implement the TestInterfaceFunction event and have it call a Print String. I place a TestActor in the level, open the level blueprint, right click and place a reference to the TestActor I placed in the level. Finally I add an Input <key> node and have it cast GameMode to TestGameMode and call TestInterfaceOnActor with TestActor. I hit play and then hit the input key.

An actual use case would be if I create a IActionInterface that basically allows me to interact with any object that extends this interface. Any odd blueprint could use this interface, but I would try and call on this interface in code. It's just a tad annoying to have to look up what the name of the function was exactly when you're otherwise almost always using auto complete.

EDIT: Here's some more discussion on it https://answers.unrealengine.com/questions/214147/grand-unified-cblueprint-cast-interface-explanatio.html.

Edited by - MichaelTraega on Jul 13 2018 2:46:23 PM
Go to Top of Page

feline
Whole Tomato Software

United Kingdom
17095 Posts

Posted - Jul 14 2018 :  08:54:42 AM  Show Profile  Reply with Quote
Thank you for the code, this makes a bit more sense now. I have also found this page on flags that can be passed to UFUNCTION:

https://docs.unrealengine.com/latest/INT/Programming/UnrealArchitecture/Reference/Functions/Specifiers/BlueprintNativeEvent/index.html

So, to check if I understand correctly, given the pretend code:

UINTERFACE(MinimalAPI, BlueprintType)
class UTestInterface : public UInterface
{
	GENERATED_BODY()
};

class ITestInterface
{
	GENERATED_BODY()

public:

	UFUNCTION(BlueprintNativeEvent, Category = "Test Interface")
	void TestInterfaceFunction();

	UFUNCTION(BlueprintNativeEvent, Category = "Test Interface")
	void AnotherInterfaceFunction();

	UFUNCTION(BlueprintImplementableEvent, Category = "Test Interface")
	void BlueprintOnlyFunction();
};

// Skip a bit

void ATestGameMode::TestInterfaceOnActor(AActor* Actor)
{
	// Valid call, and you want this generated function name in the interface member listbox
	ITestInterface::Execute_TestInterfaceFunction(Actor);
	
	// Valid call, and you want this generated function name in the interface member listbox
	ITestInterface::Execute_AnotherInterfaceFunction(Actor);

	// INVALID call, so don't generate this method name
	ITestInterface::Execute_BlueprintOnlyFunction(Actor);
}

but what about the parameter list for these generated function calls? The "Actor" parameter makes sense, since this is the object instance we are calling the functions for. Except that it is added to the parameter list. So what happens if one of these BlueprintNativeEvent functions takes parameters?

zen is the art of being at one with the two'ness
Go to Top of Page

MichaelTraega
Senior Member

USA
25 Posts

Posted - Jul 16 2018 :  10:59:06 AM  Show Profile  Reply with Quote
1. BlueprintImplementableEvents also works with this. What doesn't work are plain UFUNCTION()s because they can't be overridden in BP, so an Execute_ function won't compile. But any Blueprint[...]Event will be given a corresponding Execute_. You can see generated code at the bottom of this post.
2. The argument list just gets prepended with a UObject* for the interfaced object. So the existing arguments still work, they just have to come after Actor in my example code. See below.


// TestInterface.h
class ITestInterface
{
	GENERATED_BODY()

public:

	UFUNCTION(BlueprintNativeEvent, Category = "Test Interface")
	void TestInterfaceFunction(bool bInBool, const FString& InString); // const and & were required for this to compile with FString for some reason

	UFUNCTION(BlueprintImplementableEvent, Category = "Test Interface")
	void TestInterfaceFunction2(bool bInBool, int32 InInt);
	
	UFUNCTION()
	virtual void TestInterfaceFunction3();
};



// TestGameMode.cpp
void ATestGameMode::TestInterfaceOnActor(AActor* Actor)
{
	ITestInterface::Execute_TestInterfaceFunction(Actor, true, TEXT("Won't compile without this arg"));
	ITestInterface::Execute_TestInterfaceFunction2(Actor, false, 42);
	ITestInterface::Execute_TestInterfaceFunction3(Actor);  // error: Execute_TestInterfaceFunction3 not found
}



// TestInterface.gen.cpp
	IMPLEMENT_CLASS(UTestInterface, 2529688523);
	static FCompiledInDefer Z_CompiledInDefer_UClass_UTestInterface(Z_Construct_UClass_UTestInterface, &UTestInterface::StaticClass, TEXT("/Script/Blackbird"), TEXT("UTestInterface"), false, nullptr, nullptr, nullptr);
	DEFINE_VTABLE_PTR_HELPER_CTOR(UTestInterface);
	static FName NAME_UTestInterface_TestInterfaceFunction = FName(TEXT("TestInterfaceFunction"));
	void ITestInterface::Execute_TestInterfaceFunction(UObject* O, bool bInBool, const FString& InString)
	{
		check(O != NULL);
		check(O->GetClass()->ImplementsInterface(UTestInterface::StaticClass()));
		TestInterface_eventTestInterfaceFunction_Parms Parms;
		UFunction* const Func = O->FindFunction(NAME_UTestInterface_TestInterfaceFunction);
		if (Func)
		{
			Parms.bInBool=bInBool;
			Parms.InString=InString;
			O->ProcessEvent(Func, &Parms);
		}
		else if (auto I = (ITestInterface*)(O->GetNativeInterfaceAddress(UTestInterface::StaticClass())))
		{
			I->TestInterfaceFunction_Implementation(bInBool,InString);
		}
	}
	static FName NAME_UTestInterface_TestInterfaceFunction2 = FName(TEXT("TestInterfaceFunction2"));
	void ITestInterface::Execute_TestInterfaceFunction2(UObject* O, bool bInBool, int32 InInt)
	{
		check(O != NULL);
		check(O->GetClass()->ImplementsInterface(UTestInterface::StaticClass()));
		TestInterface_eventTestInterfaceFunction2_Parms Parms;
		UFunction* const Func = O->FindFunction(NAME_UTestInterface_TestInterfaceFunction2);
		if (Func)
		{
			Parms.bInBool=bInBool;
			Parms.InInt=InInt;
			O->ProcessEvent(Func, &Parms);
		}
	}
Go to Top of Page

feline
Whole Tomato Software

United Kingdom
17095 Posts

Posted - Jul 17 2018 :  1:56:38 PM  Show Profile  Reply with Quote
Thank you for taking the time to explain, I think I am getting this now. This is an interesting system, and reading some of the posts you have linked to I am starting to see where it comes from, and why it works this way.

I just want to double check something. On this page:

https://docs.unrealengine.com/latest/INT/Programming/UnrealArchitecture/Reference/Functions/Specifiers/BlueprintNativeEvent/index.html

there are 9 different Blueprint* function specifiers. Do you want VA to suggest "Execute_" function calls for all 9? My first reading of the page was that only "BlueprintNativeEvent" has a description that mentions the function getting a default native implementation. But I am now thinking I mis-understood.

It's down to the Unreal Engine to decide if a given Execute_ function call works / exists, but it is safe to make the call, since the plumbing will exist for any of the 9 Blueprint* function specifiers.

zen is the art of being at one with the two'ness
Go to Top of Page

MichaelTraega
Senior Member

USA
25 Posts

Posted - Jul 17 2018 :  2:12:58 PM  Show Profile  Reply with Quote
Not all 9. Just BlueprintNativeEvent and BlueprintImplementableEvent only, at least as far as I know. Sorry for the confusion. The other 7 specifiers do not make a function overrideable in blueprint. Only the 2 I mentioned and therefore they're the only relevant ones.
Go to Top of Page

feline
Whole Tomato Software

United Kingdom
17095 Posts

Posted - Jul 18 2018 :  10:43:54 AM  Show Profile  Reply with Quote
Thank you. I have put in a feature request for this, and hopefully I have condensed all of this down into a fairly easy to follow description

case=117842

zen is the art of being at one with the two'ness
Go to Top of Page
  Previous Topic Topic Next Topic  
 New Topic  Reply to Topic
 Printer Friendly
Jump To:
© 2019 Whole Tomato Software, LLC Go To Top Of Page
Snitz Forums 2000