Author |
Topic |
|
MichaelTraega
Senior Member
USA
25 Posts |
Posted - Jul 11 2018 : 3:14:06 PM
|
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
19025 Posts |
Posted - Jul 13 2018 : 1:53:39 PM
|
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 |
|
|
MichaelTraega
Senior Member
USA
25 Posts |
Posted - Jul 13 2018 : 2:31:21 PM
|
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 |
|
|
feline
Whole Tomato Software
United Kingdom
19025 Posts |
Posted - Jul 14 2018 : 08:54:42 AM
|
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 |
|
|
MichaelTraega
Senior Member
USA
25 Posts |
Posted - Jul 16 2018 : 10:59:06 AM
|
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);
}
}
|
|
|
feline
Whole Tomato Software
United Kingdom
19025 Posts |
Posted - Jul 17 2018 : 1:56:38 PM
|
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 |
|
|
MichaelTraega
Senior Member
USA
25 Posts |
Posted - Jul 17 2018 : 2:12:58 PM
|
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. |
|
|
feline
Whole Tomato Software
United Kingdom
19025 Posts |
Posted - Jul 18 2018 : 10:43:54 AM
|
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 |
|
|
Pixlor
New Member
Singapore
8 Posts |
Posted - Feb 24 2023 : 07:34:31 AM
|
It's been many years but I'm having the same problem. Is this still being considered as an added feature? Intellisense recognizes it btw.
Konrad |
|
|
feline
Whole Tomato Software
United Kingdom
19025 Posts |
Posted - Feb 24 2023 : 12:48:03 PM
|
This is still something we are considering doing. Do you have:
VA Options -> Game Development -> Index generated code (requires restart)
turned On or Off? This wasn't a setting when I last looked at this, so I am not sure what, if any, effect turning this On would have on this. |
zen is the art of being at one with the two'ness |
|
|
Pixlor
New Member
Singapore
8 Posts |
Posted - Mar 01 2023 : 07:06:17 AM
|
Thanks for the quick help; however, it doesn't fix the problem.
I tried it and and it doesn't give the suggestions for Execute_MyFunction.
|
|
|
feline
Whole Tomato Software
United Kingdom
19025 Posts |
Posted - Mar 02 2023 : 06:59:39 AM
|
I am trying to set up a test case here that compiles, so I can see if there are any obvious ways to get VA to pick up these functions. I am testing with VS2022, VA 2476 and UE 4.27
I am working in a very simple C++ test game project that I set up.
I have added a new C++ class that is derived from UInterface. I have reached this point with my header file for my new class:
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "TestInterface.generated.h"
UINTERFACE(MinimalAPI, BlueprintType)
class UTestInterface : public UInterface
{
GENERATED_BODY()
public:
// an extra Execute_ function will be created for this function
UFUNCTION(BlueprintNativeEvent, Category = "Test Interface")
void TestInterfaceFunction(bool bInBool, const FString& InString);
// an extra Execute_ function will be created for this function
UFUNCTION(BlueprintImplementableEvent, Category = "Test Interface")
void TestInterfaceFunction2(bool bInBool, int32 InInt);
};
/**
*
*/
class UE4_TESTING_API ITestInterface
{
GENERATED_BODY()
public:
void TestInterfaceFunction(bool bInBool, const FString& InString);
void TestInterfaceFunction2(bool bInBool, int32 InInt);
};
void simplyCallExecuteFunctions()
{
AActor *pActorHere = 0;
ITestInterface *pInterface;
// this line does NOT compile
// VA DOES suggest the function however
// and Alt-G on this function name takes me to the file "TestInterface.gen.cpp"
pInterface->Execute_TestInterfaceFunction(pActorHere, true, "Calling this function directly");
}
I know virtually nothing about Unreal Engine, since I don't use it, but I do work on making sure VA works correctly with it. So I am not sure what I am doing wrong here. But also VA is suggesting the generated functions for me, so I am getting a different result to you. |
zen is the art of being at one with the two'ness |
|
|
|
Topic |
|