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
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.
-
We first need to create a class which will store all of our Blueprint Functions:
- The @unreal.uclass() decorator tells Unreal to expose it to the Editor
- The
PyDemoBPLibrary
class name is arbitrary, name it uniquely as you please! - The unreal.BlueprintFunctionLibrary base class handles everything else
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.
- @unreal.ufunction() converts our Python function into a Blueprint Graph node, all of our settings will go in here.
static=True
tells Unreal that aself
arg is not expected, all of our functions will have this- Any Python docstring will also show in Unreal as the tool tip
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- to provide
str, bool, int
you tell unreal to expectstr, bool, int
- To return
str, bool, int
you tell unreal to expectint, bool, str
- That's right, the return is reverse order!
- Unreal will also add a bogus
returnValue
bool that does nothing - This example uses a list of
str
however it can be any data type, evenunreal.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
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.
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!") |
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!" |
note: It is important to always return the expected type to Unreal, Unreal will ignore anything that doesn't match the expected type
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 |
The bogus returnValue will be revisited later in the HidePin metadata arg below
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 is one of the strengths of Python for Editor Utilities, sorting in Python is much easier than Blueprints
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.
- The
|
separator is how you set multiple depth levels in the menu - The string provided to
DefaultToSelf
must match a kwarg name exactly - This decorator parameter is handy for any actor-focused functions
- This metadata parameter does have other potential uses, but its #1 use for me is to hide that bogus
returnValue
- the
Items
variable in the graph is an Array ofMeta Item Data
. this class is a Blueprint asset created in the Editor Meta Item Data
's class inherits fromEditor Utility Object
- You still need to provide the
ret
andparams
, use a parent class of what will actually be provided
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.
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 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
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 |
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 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 |
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
)
) |
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!
-
There's a lot we can do when it comes to setting up Python-based BP Function Libraries.
It has some quirks, but it presents a lot of power and versatility to extending editor functionality without needing to know C++.
Here's some additional links I found useful or learned from: