Announcement

Collapse
No announcement yet.

Referencing Blueprint Interfaces as UPROPERTY

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Referencing Blueprint Interfaces as UPROPERTY

    I have created a Blueprint interface in C++, like this:

    Code:
    /// Implemented by dialogs and menus that can be controlled with keyboard and gamepad
    class NUCLEX_API IButtonControllableDialog {
    
      GENERATED_BODY()
    
      /// Accepts the currently selected dialog option
      public: UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category="UI")
      void Accept();
    
      /// Cancels the currently selected dialog
      public: UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category="UI")
      void Cancel();
    
      // ...
    
    };
    And inherited said interface in a pure Blueprint class:

    Click image for larger version

Name:	inheritinblueprint.png
Views:	32
Size:	26.2 KB
ID:	1674907

    Now I thought my C++ player controller could be given a property like this:

    Code:
    /// Dialog to which input is currently being sent (can be null if no dialog is active)
    public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Transient, Category="UI")
    TScriptInterface<IButtonControllableDialog> ActiveDialog;
    But as I found in the Interfaces in C++ wiki article, that does not work for Blueprint interfaces implemented in Blueprint. Instead, I have to check:

    Code:
    this->ActiveDialog->GetClass()->ImplementsInterface(UButtonControllableDialog::StaticClass())
    Fine.

    But if I assign the ActiveDialog property in Blueprint, even though it compiles fine, it instead assigns NULL.

    Click image for larger version

Name:	assigningfromblueprint.png
Views:	23
Size:	92.2 KB
ID:	1674908

    It works if I change the property type to UObject *, but that would totally remove any type information. Blueprinters could assign literally anything :-/

    Funnily, if I create a class with an IButtonControllableDialog property in Blueprint and nativize it, the same TScriptInterface<IButtonControllableDialog> property is generated.


    How can I create a property of type IButtonControllableDialog that works for both C++ and Blueprint classes?

    #2
    So this is really the state of things?

    Either expose properties as (UObject *) and lose any indication as to which interface type is supposed to be assigned to them,

    or expose properties as (UMyBlueprintInterface *) and lose the ability to ever implement the interface using Blueprints?

    Comment


      #3
      Interface implemented to Blueprints using the Editor is an UInterface sub object attached to the Blueprint.
      Casting will never work like that, this is why you get null.

      Also there's no reason to cast anything to call interface methods from Blueprint and Interfaces cannot have properties so I have no idea why you even want to cast them.
      | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

      Comment


        #4
        Please read my original post.


        A) I have a C++ class (let's say, a custom PlayerController) that has a UPROPERTY:

        Now I thought my C++ player controller could be given a property like this:
        Code:
        /// Dialog to which input is currently being sent (can be null if no dialog is active)
        public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Transient, Category="UI")
        TScriptInterface<IButtonControllableDialog> ActiveDialog;
        I am not trying to add a UPROPERTY to a blueprint interface.

        Comment


          #5
          B) I do not want to cast anything and know there is no need to. All blueprint interface calls are by name (and I can see exactly how someone at Epic attempted to design a system for actual method calls in UE C++, failed and clobbered stuff together to arrive at the current state of things)

          I want some semblance of type safety. I'm given two choices in my PlayerController:


          Choice 1:

          Code:
          /// Dialog to which input is currently being sent (can be null if no dialog is active)
          public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Transient, Category="UI")
          TScriptInterface<IButtonControllableDialog> ActiveDialog;
          The Kismet editor shows the property as being of type IButtonControllableDialog. Nice, the blueprint monkey knows which type to assign to it. Except when he creates a blueprint class and assigns it, it silently fails. Yes. it silently fails and assigns null.


          Choice 2:

          Code:
          /// Dialog to which input is currently being sent (can be null if no dialog is active)
          public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Transient, Category="UI")
          UObject *ActiveDialog;
          The Kismet editor shows an Object pin. The blueprint monkey could assign anything to it and my player controller would eat it. Only when I call IButtonControllableDialog::SomeMethod_Execute() things would start going wrong.
          Last edited by cygon; 10-26-2019, 06:25 AM.

          Comment


            #6
            UPROPERTY ( EditAnywhere, meta = (AllowedClasses="ButtonControllableDialog") )
            UObject *ActiveDialog;
            | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

            Comment


              #7
              Thank you very much!

              That totally fixes the pain on the Blueprint side for me

              Erm, correction, it seems to do nothing.

              Code:
              /// Dialog to which input is currently being sent (can be null if no dialog is active)
              public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Transient, Category="UI")
              TScriptInterface<IButtonControllableDialog> ActiveDialog;
              
              /// Dialog to which input is currently being sent (can be null if no dialog is active)
              public: UPROPERTY(
                EditAnywhere, BlueprintReadWrite, Transient, Category="UI",
                meta = (AllowedClasses = "ButtonControllableDialog")
              )
              UObject *SameWithBCD;
              
              /// Dialog to which input is currently being sent (can be null if no dialog is active)
              public: UPROPERTY(
                EditAnywhere, BlueprintReadWrite, Transient, Category="UI",
                meta = (AllowedClasses = "Gooblefoob")
              )
              UObject *SameWithGooblefoob;
              
              /// Dialog to which input is currently being sent (can be null if no dialog is active)
              public: UPROPERTY(
                EditAnywhere, BlueprintReadWrite, Transient, Category="UI",
                meta = (AllowedClasses = "IButtonControllableDialog")
              )
              UObject *SameWithIBCD;
              
              /// Dialog to which input is currently being sent (can be null if no dialog is active)
              public: UPROPERTY(
                EditAnywhere, BlueprintReadWrite, Transient, Category="UI",
                meta = (AllowedClasses = "UButtonControllableDialog")
              )
              UObject *SameWithUBCD;
              Click image for larger version

Name:	variations.png
Views:	28
Size:	132.8 KB
ID:	1678472

              According to the docs it should at least affect the asset picker, but that doesn't seem to happen either.

              https://wiki.unrealengine.com/UPROPERTY#AllowedClasses

              So unless I'm missing something, I'm still at square one.
              Last edited by cygon; 10-26-2019, 02:51 PM.

              Comment


                #8
                Force users to set variable from Details Panel.
                Do not allow BlueprintReadWrite, if it must be set in graph then only a custom Kismet K2Node can do that filtering.
                | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

                Comment

                Working...
                X