Blueprint Function Libraries

A more verbose method for calling Python inside of an Editor Asset is to create Python BP Function Libraries. This is only recommended for internal projects that can manager their UE environments

A Warning


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.


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("Printed a message via 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!"):
    print(f"Provided input: {user_input}")
  • 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

@unreal.ufunction(static=True, ret=str)
def return_test():
    return "cool!"
  • ret Is where we tell it what return data type to expect

Multiple Input / Output

For inputs we can add to the list in sequential order of our Python function's params:

@unreal.ufunction(static=True, params=[str, bool, int])
def multiple_input_test(in_str, in_bool, in_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, another option is to use:
          ret=(str, bool, int)[::-1]
    """
    return "Awesome", True, 5
  • To return str, bool, int you tell unreal to expect int, bool, str

    • That's right, the return is reverse order!

    • Another option is to use ret=(str, bool, int)[::-1] if we want to keep it visually consistent

  • Unreal will also add a bogus returnValue bool that does nothing

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):
    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

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:
    return os.environ.get("USER", "unknown user")

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():
    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():
    pass
  • You can find a function buy its name, its category, or any of its keywords

Key Words

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():
    pass

Default To Self

The DefaultToSelf meta dict member will populate the given kwarg 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):
    pass

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=(str, bool, int)[::-1], 
    meta=dict(HidePin="returnValue")
)
def multiple_returns_fixed_test():
    return "Awesome", True, 5

Determines Output Type

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

@unreal.ufunction(
    static=True, 
    ret=unreal.Object,
    params=[unreal.Object],
    pure=True,
    meta=dict(DeterminesOutputType="object_to_match")
)
def match_object(object_to_match):
    pass
  • This can help inform the Blueprint Graph when returning BP Assets created in the Editor

  • ret and params still need to be provided, use an appropriate parent class


Advantages

The main advantage of this method is its verbosity, you can do so much more with this method than what's possible with Execute Python Script nodes.

Disadvantages

A major disadvantage of this method is the instability covered in the warning section above. It is possible to mitigate the Editor Startup issues, but for public release projects it can't be guaranteed that other users will take the appropriate steps.

A minor inconvenience is that we have to provide our own Success? return, if we want it. If a Python error occurs during one of these nodes, it won't stop the Blueprint Graph from continuing on to the next node.

Last updated