Interface as parameter on call from Blueprint to C++

Edit 12.03.2017

On request I have created a simple sample project that reproduces the error. Here it is: [InterfaceTest Project][1]

The Project contains the following contents:

  • Interface (C++) named ListenerInterface
  • Two UMG UserWidgets implementing the interface (oververriding the interface event OnPropertyChanged)
    • One Widget implements the interface directly in Blueprint (via the Class Settings property sheet)
    • The Other Widget has a C++ base class (UMyCppUserWidget) that implements the interface
  • An Actor BP_MyActor with a component MyActorComponent (and owning the two widgets)
  • The MyActorComponent has the function RegisterListener where the ListenerInterface can be registered
  • The member function UMyActorComponent::ChangePropertyAndNotiyListener changes the property value and notifies the registered listener by calling the Interface function callback OnPropertyChanged, that is implemented/overridden by the both user widgets.

Steps to reproduce:

  1. Start the editor from visual studio or attach the debugger to the editor.
  2. Start the game inside the editor
  3. Enable Mouse cursor by pressing shift+F1
  4. Click the first button on the left widget

This should trigger the check() assertion as shown in this picture: Note that the InterfacePointer is invalid (NULL), while the ObjectPointer looks good.

When doing the same steps in the right widget, you will get the following (using a manual breakpoint): As you can see the InterfacePointer is valid here:

(I cannot attach more screenshot, please let me know if you need it, I will then delete the screens from the original message.)

Please let me know if you need any further information.

Original Post below

I’m implementing a listener mechanism for variable replication inside actor components. The listener interface shall be implemented by interested classes or blueprints.
The classes/blueprints that implement the interface must register themselves via function call on the Component.
The Component has a UPROPERTY(ReplicatedUsing) from where the notifications are sent to the registered listener, if any.

This does not work if a blueprint implements the interface, the picture shows the registration call, where the debugger shows the correct object reference, but InterfacePointer is null..

As the next picture shows, it does work if I rebase the blueprint to a C++ base, the C++ base implements the interface. The regisitration is still called from blueprint.

Here is the definition of the interface:

#pragma once
#include "ComponentReplicationListener.generated.h"

UINTERFACE(BlueprintType)
class UComponentReplicationInterface : public UInterface
{
	GENERATED_UINTERFACE_BODY()
};

inline UComponentReplicationInterface::UComponentReplicationInterface(const class FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{}

class IComponentReplicationInterface
{
	GENERATED_IINTERFACE_BODY()
public:

	UFUNCTION(BlueprintNativeEvent, Category=ComponentReplicationInterface)
	void OnComponentReplication(class UEntityComponentBase* replicatedComponent);
};

Here is the blueprint snippet of the registration. The Blueprint is derived from UUserWidget.

127475-blueprint.png

This is the c++ base, for which it is working.

#pragma once

#include "Blueprint/UserWidget.h"
#include "events/ComponentReplicationListener.h"
#include "RuneInTreeWidget.generated.h"

/**
 * 
 */
UCLASS(BlueprintType)
class GAME_API URuneInTreeWidget : public UUserWidget, public IComponentReplicationInterface
{
	GENERATED_BODY()
public:
	
	virtual void OnComponentReplication_Implementation(class UEntityComponentBase* replicatedComponent) override;
};

Hey Wurmloch83-

I was able to create an interface, however I don’t have a reference for what UEntityComponentBase is meant to be. I’m also not sure what your ULevelComponent class is parented from. Can you provide the full setup steps you’re using when you run into this issue or a small sample project that shows the issue occurring?

Yes, give me a few days and I will try to reproduce this in a sample project. Maybe I will find time on the weekend.

Hi Doug,

I have updated the question and attached a sample project to reproduce the problem. Please let me know if you need further information.

Hey Wurmloch83-

Thank you for the sample project, I was able to reproduce the behavior and have entered a report for the issue here: Unreal Engine Issues and Bug Tracker (UE-42986) . You can track the report’s status as the issue is reviewed by our development staff. Please be aware that this issue may not be prioritized or fixed soon.

Cheers

Doug Wilson

I ran into something very similar, passing an interface reference paramter to a C++ UFUNCTION in a blueprint class that implements a C++ UINTERFACE from blueprint instead of from its C++ base class ends up with the TScriptInterface having a null InterfacePointer.

I then tried passing it as a UObject instead of an interface ref and casting it to the interface with Cast; this failed too. After trying it that way I found this via google:

The solution in the end using that was:

void AFooBasePlayerController::InteractWith(TScriptInterface<IFooInteractable> const & Interactable)
{

	if (Interactable.GetObject() && Interactable.GetObject()->GetClass()->ImplementsInterface(UFooInteractable::StaticClass()))
	{
		if (IFooInteractable::Execute_IsCurrentlyInteractable(Interactable.GetObject()))
		{
			[...]
		}
	}
}

Slight addition to this:

If the TScriptInterface only has a null InterfacePointer, the above works, but if you try and pass the TScriptInterface on a server RPC it will work if called on the server, and fail if called from the client (the RPC will come through, but both ObjectPointer and InterfacePointer will be null). So if you need to pass a C++ interface on an RPC that was only included on the blueprint object and not the C++ base, you should make the RPC parameter a plain UObject, then check for the interface with

TheObjectParam != nullptr && TheObjectParam->GetClass()->ImplementsInterface(UFooInteractable::StaticClass()))