x

Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

How to get an interface pointer variable to work w/UPROPERTY()

Hello, I am attempting to have an interface pointer variable that is declared in the header be VisibleAnywhere, BlueprintReadOnly in the UPROPERTY() but when I compile it gives me an error: UPROPERTY pointers cannot be interface - did you mean TScriptInterface?

But I don't know what that means or how TScriptInterface's work... If anybody can point me(excuse the pun) in the right direction or just flat out tell me how to fix this, that would greatly appreciated.

the header:

 protected:
 
                UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Interface Variable")
                IMyInterface* SelfInterface;
Product Version: UE 4.14
Tags:
more ▼

asked Jan 26 '17 at 02:10 PM in C++ Programming

avatar image

Oldsiren
161 25 25 31

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

1 answer: sort voted first

Hi, you need to do this:

 UPROPERTY(...)
 TScriptInterface<IMyInterface> SelfInterface;

Hope this helps,

Steve

more ▼

answered Jan 26 '17 at 02:16 PM

avatar image

Steve Robb STAFF
2.8k 58 31 101

avatar image Oldsiren Jan 26 '17 at 02:47 PM

Ok, but I have three questions. How would I set the value in code like say the Constructor I was setting the variable to nullptr how would I do that with TScriptInterface? And I also set the variable in BeginPlay using a cast what would be the equivalent of that for TScriptInterface? And how would I check if TScriptInterface is valid?

avatar image Steve Robb STAFF Jan 26 '17 at 03:22 PM

You can set the value in the constructor in the same way you would set a pointer. The pointer type must be null or one derived from UObject though - an IMyInterface* won't work:

 SelfInterface = nullptr;                   // ok
 SelfInterface = UObjectPtr;                // ok
 SelfInterface = (IMyInterface*)UObjectPtr; // won't work

For casting, you can just call GetObject() and cast as usual:

 CastChecked<UWhatever>(SelfInterface.GetObject())->WhateverProperty = 10;

And checking if it's valid is the same as any other pointer:

 if (SelfInterface)
 {
     ...
 }

Steve

avatar image Oldsiren Jan 26 '17 at 03:31 PM

Ok, thank you very much for the help. Just for clarification on the Cast would the below script work?

 SelfInterface = CastChecked<IMyInterface>(SelfInterface.GetObjectRef());
avatar image Steve Robb STAFF Jan 26 '17 at 03:38 PM

If your interface is an UINTERFACE(), then yes, that should work.

You should use GetObject() rather that GetObjectRef() though. I don't think GetObjectRef() should be public.

Steve

avatar image Oldsiren Jan 26 '17 at 03:52 PM

So I would put UMyInterface or add static class, instead of IMtInterface? When I enter GetObject it comes up with GetObjectRef, GetObjectW, and GetInterface. I really appreciate you helping clear this up for me :)

avatar image Steve Robb STAFF Jan 26 '17 at 04:23 PM

You would put IMyInterface:

 IMyInterface* InterfacePtr = CastChecked<IMyInterface>(SelfInterface.GetObject());
 InterfacePtr->DoThing();

But if SelfInterface is already an TScriptInterface then you don't need a cast, because you know it's already of that type. Instead, you can just call it directly:

 SelfInterface->DoThing();

You would use your code above if you needed to discover an interface other than IMyInterface (and you'd probably use Cast instead of CastChecked, if you want to handle the possibility of failure).

GetObject() will work. GetInterface() should work but doesn't because it'll call the FScriptInterface base class function which just returns a void* instead of InterfaceType*. TScriptInterface is in need of some API love. :-p

GetObjectW is probably cropping up because of the Windows headers, which we do not have any control over:

 #ifdef UNICODE
 #define GetObject  GetObjectW
 #else
 #define GetObject  GetObjectA
 #endif // !UNICODE

Steve

avatar image Oldsiren Jan 26 '17 at 04:43 PM

So with TScriptInterface how would I use the cast to set the pointer to that interface that I would want it to be, so that its no longer null?

avatar image Steve Robb STAFF Jan 26 '17 at 05:40 PM

As I said above:

 SelfInterface = UObjectPtr;

You can't set it to an IMyInterfacePtr* directly, only to one which is both convertible to both UObject* and IMyInterfacePtr*.

Steve

avatar image Oldsiren Jan 26 '17 at 05:43 PM

Ok I found out how to set the TScriptInterface's interface to another interface. Thank you very much for you assistance! Example for better explanation below:

  Called when the game starts or when spawned
 void ALeverActor::BeginPlay()
 {
     Super::BeginPlay();
 
     //Since I'm doing this only in BeginPlay,
     //I'm gonna make a temp variable that gets deleted after BeginPlay is called
     IMyInterface* tempMyInterface = nullptr;
 
     tempMyInterface = Cast<IMyInterface>(this);
 
     //Both of these have to be set!
     SelfInterface.SetInterface(tempMyInterface);
 
     //Since I'm getting the interface in self/this I'm setting the object for this.
     SelfInterface.SetObject(this);
 
     if (SelfInterface)
     {
         UE_LOG(LogTemp, Warning, TEXT("SelfInterface is valid"));
     }
 
 }
avatar image Steve Robb STAFF Jan 26 '17 at 05:46 PM

You don't need to do all of this:

 IMyInterface* tempMyInterface = nullptr;
 tempMyInterface = Cast<IMyInterface>(this);
 SelfInterface.SetInterface(tempMyInterface);
 SelfInterface.SetObject(this);

You just need to do this:

 SelfInterface = this;

Steve

avatar image The Space Bar Rider Sep 06 '18 at 12:39 PM

Hi, I follow what you said here. It work pretty well, appart when I'm testing if it's valid. It's always return false ! :/ I've tested with a log, and the "TScriptInterface<>->GetObject()->GetName() print me the good think. So my pointer is not false. So I have no idea why the test is always false.

 // Called when the game starts
 void UActionManager::BeginPlay()
 {
     Super::BeginPlay();
 
     // ...
     if ( GetOwner()->GetClass()->ImplementsInterface( UActionable::StaticClass() ) )
     {
         OwnerAsActionable = GetOwner();
         UE_LOG( LogPacInit, Warning, TEXT( "%s -> %s (Component Owner) implement Actionable Interface" ), *GetName(), *OwnerAsActionable.GetObject()->GetName() );
     }
     else
     {
         UE_LOG( LogPacInit, Warning, TEXT( "%s -> %s (Component Owner) don't implement the Actionable Interface" ), *GetName(), *GetOwner()->GetName() );
     }
 }
 /........
 void UActionManager::OnGainFocus( APawn * Instigator )
 {
     if ( !OwnerAsActionable )
     {
         UE_LOG( LogPacActionSystem, Warning, TEXT( "%s->OnGainFocus : The component owner don't implement Actionable Interface !" ), *GetName());
         return;
     }
     OwnerAsActionable->OnGainFocus( Instigator );
 }
avatar image Steve Robb STAFF Sep 07 '18 at 01:45 PM

The implementation of TScriptInterface::operator bool() and TScriptInterface::operator->() are both implemented in terms of the same function, so they should be consistent.

Steve

avatar image The Space Bar Rider Sep 07 '18 at 02:33 PM

In fact, after some verifications, the SourceObject is good (When I use GetObject(), it return me the good pointer), but the InterfacePointer is Always false.

The thing is, that the actor that implement the interface is Blueprint Actor inherited from simple Actor. And in Class Settings, I implement the interface. Maybe that is the reason why it don't work.

I can call Interface functions from blueprint, but when I call interface functions from C++ I got a crash (BReackpoint reached)

avatar image Steve Robb STAFF Sep 07 '18 at 02:41 PM

Are you setting this TScriptInterface as a property via BPs? It can only be set by native C++, not Blueprints or any other system.

TScriptInterface is like a tuple of UObject*` and IMyInterface*. It holds a UObject* to keep the GC happy and a IMyInterface* to make calls against. Setting it in native code, you have to pass the IInterface* - it will copy that and then cast back to the UObject* to store that too.

But if you set it in any other way (e.g. reflection, via BPs), then you will only be setting the UObject* part. That sounds like it could be the reason why you have an object but no interface.

Steve

avatar image The Space Bar Rider Sep 07 '18 at 04:01 PM

I'm setting the TScriptInterface via C++. But The Actor that implement the interface is created by BP. But I finally got it to Work like that : IYourInterface::Execute_YourFunctionName( ActorPointerWhichExecuteTheFunction, params .... ); THanks for the answers anyway.

But the thing is the IMyInterface is always at 0x00000 in debuger. (So nullptr) I use MyTScriptInterface = MyObjectPtr to set it !

(comments are locked)
10|2000 characters needed characters left
Viewable by all users
Your answer
toggle preview:

Up to 5 attachments (including images) can be used with a maximum of 5.2 MB each and 5.2 MB total.

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question