Skip to content

Latest commit

 

History

History
492 lines (338 loc) · 12.5 KB

02_blueprint_function_libraries.md

File metadata and controls

492 lines (338 loc) · 12.5 KB

Python BP Function Libraries in Unreal

Python based Blueprint Functions allow more users access to extend the functionality of the Editor. It might not be able to do everything that c++ can, but a lot of functionality is already exposed and the potential is already beyond impressive!

This page covers the bp_library python module


An Important Warning

    This page covers an implementation that is not recommended for general use by Epic.

    For general use it is recommended to use the Epic-provided Execute Python Script Node. Here is an example using the Execute Python Script node in Blueprints:

    The input and output variables can be declared in the Details Panel as wildcard data types:


    The rest of this page will cover an implementation that requires more safety measures to use effectively. The Making Python Blueprint Functions Safer documentation page covers the work required to make this approach safer to use, all of which is provided in the provided Unreal plugin and implemented on the meta_viewer tool.


Declaring a BP Function Library class

    We first need to create a class which will store all of our Blueprint Functions:
    import unreal
    
    @unreal.uclass()
    class PyDemoBPLibrary(unreal.BlueprintFunctionLibrary):
        """Blueprint functions declared in this class will be available in Editor"""
        # functions to follow...

    This PythonFunctionLibrary class will be where all following function node examples are declared.


    For the rest of this page we'll be adding functions to this class, any function added to this class will be made available to the Blueprint Graph.

Declaring Functions - Decorator Overview

    Functions are exposed to Unreal through decorators, there are two areas this page will focus on. This section is on the expected data: what's our input and what's our return. In the following section we'll cover how to organize and modify the behavior of the function via metadata.

    Basic function example

      For all blueprint function this is our starting block:

      @unreal.ufunction(static=True)
      def basic_function_test():
          """Python Blueprint Node -- run Python logic!"""
          print("Running python!")
      • @unreal.ufunction() converts our Python function into a Blueprint Graph node, all of our settings will go in here.
      • static=True tells Unreal that a self arg is not expected, all of our functions will have this
      • Any Python docstring will also show in Unreal as the tool tip

    Single Input / Output

      To pass blueprint data to Python and back we must tell it what type of data we're expecting to provide/receive:

      @unreal.ufunction(static=True, params=[str])
      def input_test(user_input = "cool!"):
          """Python Blueprint Node -- print the text input"""
          print(f"Provided input: {user_input}")

      @unreal.ufunction(static=True, ret=str)
      def return_test():
          """
          Python Blueprint Node -- return a string!
          returns:
              str
          """
          return "cool!"
      • params Is where we map the input type of each kwarg in sequential order
        • Any default kwarg values will display in the BP Graph node
      • ret Is where we tell it what return type to expect

      note: It is important to always return the expected type to Unreal, Unreal will ignore anything that doesn't match the expected type

    Multiple Input / Output

      To pass multiple args or returns we may provide a list/tuple:

      @unreal.ufunction(static=True, params=[str, bool, int])
      def multiple_input_test(in_str, in_bool, in_int):
          """Python Blueprint Node -- multiple inputs (string, bool, int)"""
          print(
              f"{in_str} ({type(in_str)}) | "
              f"{in_bool} ({type(in_bool)}) | "
              f"{in_int} ({type(in_int)})"
          )

      @unreal.ufunction(static=True, ret=(int, bool, str))
      def multiple_returns_test():
          """Python Blueprint Node -- Return (str, bool, int)
      
          NOTE: the 'ret' decorator arg is reversed 
                from the actual python return
          """
          return "Awesome", True, 5
      • to provide str, bool, int you tell unreal to expect str, bool, int
      • To return str, bool, int you tell unreal to expect int, bool, str
        • That's right, the return is reverse order!
      • Unreal will also add a bogus returnValue bool that does nothing

      The bogus returnValue will be revisited later in the HidePin metadata arg below

    Handling Lists

      When handling lists you must use the unreal.Array(type) class and declare its content:

      @unreal.ufunction(
          static=True, ret=unreal.Array(str), 
          params=[unreal.Array(str)]
      )
      def sort_string_list_test(in_list):
          """
          Python Blueprint Node -- Sort a list of strings, 
          useful for managing options in editor tool
          """
          return sorted(in_list)
      • This example uses a list of str however it can be any data type, even unreal.actor!
      • It's okay to return a python List as well, but if any of its contents are not str it will throw an error

      This example is one of the strengths of Python for Editor Utilities, sorting in Python is much easier than Blueprints

    Pure functions (no exec in/out connections)

      For getter functions we can use the pure flag:

      @unreal.ufunction(ret= str, pure=True, static=True)
      def pure_function_test() -> str:
          """
          Python Blueprint Node -- 
          Pure functions have no execution flow pins,
          a pure function is intended for getter functions
          that do not change the state of assets in Unreal
          """
          return os.environ.get("USER", "unknown user")

      Pure functions promise not to change the state of the Unreal class calling them. They are great for getting data, running calculations on values, or performing conversions to name a few use cases.



Declaring Functions - Metadata Specifiers

    This section covers the meta arg, which represents Metadata Specifiers. Given a dict of specifiers this flag grants further control over how the Blueprint node is organized, displayed, and behaves. To learn more about Metadata Specifiers this Unreal page is a great resource.

    Category

      The Category meta dict member controls how the function is organized in the right click menu:

      @unreal.ufunction(
          static=True, 
          meta=dict(Category="demo | category | sorting")
      )
      def meta_category_test():
          """
          Python Blueprint Node --
          Category organizes this node 
          in the right click menu
          Use | to create nested levels
          
          """
          pass
      • The | separator is how you set multiple depth levels in the menu

    Key Words

      The KeyWords meta dict member registers additional words that may be used to find our function:

      @unreal.ufunction(
          static=True, 
          meta=dict(KeyWords="random arbitrary keywords")
      )
      def meta_keywords_test():
          """
          Python Blueprint Node -- 
          KeyWords help the discovery of 
          this node in the BP Graph right click menu
          """
          pass

      You can find a function buy its name, its category, or its keywords

    Compact Title

      The CompactNodeTitle meta dict member tells our function to use a compact display in the Blueprint Graph:

      @unreal.ufunction(static=True, meta=dict(CompactNodeTitle="UEPY"))
      def meta_compact_name_test():
          """Python Blueprint Node -- CompactNodeTitle"""
          pass

    Default To Self

      The DefaultToSelf meta dict member will populate the given arg with a reference to the containing BP Class that's calling it:

      @unreal.ufunction(
          static=True, 
          params=[unreal.Actor], 
          meta=dict(DefaultToSelf="target_object")
      )
      def meta_default_to_self_test(target_object):
          """
          Python Blueprint Node -- DefaultToSelf 
          (The BP Class calling this Function)
          """
          print(f"target object: {target_object}")
          pass
      • The string provided to DefaultToSelf must match a kwarg name exactly
      • This decorator parameter is handy for any actor-focused functions

    Hide Pin (Fixes Multiple Returns)

      The HidePin meta dict member tells Unreal to hide the desired pin, we can use this to fix the multiple returns example:

      @unreal.ufunction(
          static=True, 
          ret=(int, bool, str), 
          meta=dict(HidePin="returnValue")
      )
      def multiple_returns_fixed_test():
          """Python Blueprint Node -- Return (str, bool, int)"""
          return "Awesome", True, 5
      • This metadata parameter does have other potential uses, but its #1 use for me is to hide that bogus returnValue

    Determines Output Type

      The DeterminesOutputType meta dict member controls our function's return data type:

      @unreal.ufunction(
        static=True, 
        ret=unreal.Array(
          unreal.EditorUtilityObject
        ),
        params=[
          unreal.Array(unreal.EditorUtilityObject)
        ],
        pure=True,
        meta=dict(
          DeterminesOutputType="array_to_match"
        )
      )
      def get_item_data_for_euw(
        array_to_match=unreal.Array(
          unreal.EditorUtilityObject
        )
      )
      • the Items variable in the graph is an Array of Meta Item Data. this class is a Blueprint asset created in the Editor
      • Meta Item Data's class inherits from Editor Utility Object
      • You still need to provide the ret and params, use a parent class of what will actually be provided

      Without this meta decorator it would have returned an Editor Utility Object array. This allows us to return custom assets directly from Python, no post-conversion necessary!



Summary