1. Setup Unreal Python Environment
First, you need to enable the python plugin
- Open your Project, and choose Edit > Plugins from the main menu.
- In the Plugins window, go to the Scripting section.
Find the Python Editor Script Plugin in the right-hand panel, and check its Enabled box.

What’s more, we need to add IDE support for ot. Open the Settings window and navigate to Project > Python Interpreter, then click the gear and select Show all. In the Python Interpreter window, you can click the Paths button and click + to add the location of your stub file.
You will also need to raise the maximum Intellisense file size by navigating to Help > Edit Custom Properties and adding the following, note that it costs a lot memory:
idea.max.intellisense.filesize = 25000
It is also avaiable for Rider:
2. How to run your python code in Unreal Engine Editor?
There are several ways to run a python script in unreal engine, we only introduce some of them, the other can be found in unreal engine documentation:
Run the python console in output log
Create a directory in your game project directory called “PythonScripts” for managment, add then add a python file called “test_console.py” whcih implementation is:
import unreal unreal.log("called from console")
There is a log category for python called LogPython, everytime you call unreal.log, the result will be printed in this category.
Call a python script by this method is just like call a python script in console of os, which allow you to call it with parameters:
import sys import unreal unreal.log("called from console") for arg in sys.argv: unreal.log(arg)
Startup Files
In your Project Settings, you can specify any number of Python scripts that you want to run every time you open that Project. The Editor runs these scripts after the default startup Level is fully loaded.
Select Edit > Project Settings…. Under the Plugins list, select Python. Then, add your scripts to the Startup scripts setting:
I created a python file called “log_hello_when_start.py”, which is simply implemented as:
import unreal unreal.log("hello")
By blueprint
The following are the most generally used blueprint nodes about python scripting:
Node Name | Description |
---|---|
Execute Python Script | Executes the literal Python code that you pass in to or type in the Python Command input. It is the recommended way to call Python from Blueprints, and superscedes creating a new BlueprintFunctionLibrary(BPFL) type in Python. The aformentioned BPFL method causes issues when an asset is saved or loaded due to Python-generated types being transient, and is no longer officially supported. Execute Python Script can have can have custom input and output pins, which are available as variables within the Python script on the node and can be added by the properties of the node. -Inputs are set prior to running the Python script on the node, and can be read in the script. -Outputs are read after running the Python script on the node, and can be set in the script. Execute Python Script can contain multiple lines of Python code, and new-lines can be entered by using the keys Shift+Return. The Success? output is true if the Python code was executed successfully, or false otherwise. If it is false, you can find the errors in the Output Log. Node that this node cannot run files. It can only execute lines of Python code. |
Execute Python Command | Executes the literal Python code or file that you pass in to or type in the Python Script input. The node will attempt to determine based on your input whether it is literal code or a filename. -The Return Value output is true if the Python code or file was executed successfully, or false otherwise. If it is false, you can find the errors in the Output Log. |
Execute Python Command (Advanced) | Executes the literal Python code or file that you pass in to or type in the Python Script input. This node is similar to Execute Python Command, but offers some additional inputs and outputs that may be useful in some scenarios. Execution Mode indicates how you want to interpret the Python Script input. Select Execute File to force the command to treat your input as the name of a file, and to attempt to find and run that file. Any values returned by this script are printed to the log. Select Execute Script to force the command to treat your input as literal Python code, and to execute it as-is. Any values returned by this script are printed to the log. Select Evaluate Script to force the command to treat your input as literal Python code, evaluate it as-is, and return any values produced by the script in the Command Result output. If you pass a filename to the Python Script input, the File Execution Scope determines whether that file is executed in the global scope (Public) or in a sandboxed scope (Private). If you want the code in your file to be able to access variables, functions, and so on that have already been defined in the Python environment, then you will need to choose Public. However, doing so also gives the Python file the ability to redefine variables and functions. This may accidentally cause unexpected behavior. Therefore, it may be safer to use the Private scope. The Command Result output depends on the Execution Mode. When the Python Script input is executed or evaluated successfully, and the Execution Mode is Evaluate Script, this output returns the value produced by the script. When the Python Script input is executed or evaluated successfully, and the Execution Mode is either Execute File or Execute Script, this output returns None. When the Python Script input is not executed or evaluated successfully, this output contains the error information. The Log Output provides access to the full list of messages written to the Python log during the execution of the input script or file. You can iterate through this array if you need to look for specific messages written by the script. The Return Value output is true if the Python code was executed successfully, or false otherwise. If it is false, you can find the errors in the engine's Output Log, in the Log Output output pin, and in the Command Result. |
3. Python Environment & Path in UE
When you use a relative path to run a Python script, or to import another script module using the import
command in one of your scripts, the script that you run or import can be in any path that is listed in the sys.path
variable of your Python environment.
The Unreal Editor automatically adds several paths to this sys.path
list:
- The Content/Python sub-folder in your Project’s folder.
- The Content/Python sub-folder in the main Unreal Engine installation.
- The Content/Python sub-folder in each enabled Plugin’s folder.
- The Documents/UnrealEngine/Python folder inside your user directory. For example, on Windows 10, this is equivalent to
C:/Users/Username/Documents/UnrealEngine/Python
You can also add your own paths to this list using any of the approaches when mentioned before, add the path in project settings->Plugins->Python->Additional Paths
4. About the Unreal Python APi
The Python Editor Script Plugin exposes a wide range of classes and functions that you can use to interact with the Unreal Editor, the Assets in your Project, and the content in your Levels. This API is all contained in the unreal
module. To access it, import this module at the beginning of any Python script you run in the Editor’s Python environment:
import unreal
The unreal
module exposes nearly everything that is exposed from C++ to Blueprints in your Editor environment. It’s not pre-generated; it automatically reflects whatever is available in Blueprints in your Editor. As you enable new plugins in the Unreal Editor, anything those plugins expose to Blueprints also becomes available in Python as well. The same goes for any C++ code that you write in your Project and expose to Blueprints.
The Python API makes every effort to expose native Unreal APIs in a way that is as friendly as possible to Python developers. For example:
- Simple data types are transparently converted back and forth between Python and native types whenever necessary.
When you pass in a Python list, set or dict, it is automatically converted to an Unreal array, set, or map. When you retrieve a list, set, or dict returned by an API function, you are actually getting an instance of an Unreal class, but its API is fully consistent with the base Python list, set, or dict type. - Python classes maintain the same inheritance hierarchy as the native types they represent. That means, for example, that you can use the built-in Python functions
isinstance()
andtype()
to test whether an object derives from or matches a given class. - The API tries to strike a good balance between the naming conventions used in Unreal for C++ and Blueprints on one hand, and Python naming conventions on the other hand. Classes and objects in the Python API have the same names as they do in Blueprints. This is typically the same as their native types, omitting the prefix (e.g.
U
orT
). Function and property names are automatically exposed as lower-casesnake_case
. So, for example, you typically call functions likeunreal.StaticMeshActor.get_actor_transform()
. Enumeration value names are automatically exposed as upper-caseSNAKE_CASE
. - All exposed functions can accept either ordered parameters, or named parameters in any order. For example, the following two function calls are exactly equivalent:
5. Editor Extension Examples
1. Create a progress dialogs for slow operation
import unreal import time total_frame = 100 text_label = "Working with slow progress" unreal.log("start slow progress") with unreal.ScopedSlowTask(total_frame, text_label) as slow_task: slow_task.make_dialog(True) for i in range(total_frame): # Sleep for 0.25 seconds time.sleep(0.25) if slow_task.should_cancel(): break slow_task.enter_progress_frame(1)
2. Changing Editor Property
A good way to change properties in multiple assets:
import unreal search_path = "/Game" blueprint_generated_class = unreal.load_object(None, "/Game/StaticMeshActor.StaticMeshActor_C") if blueprint_generated_class is None: unreal.log("obj is none") blueprint_cdo = unreal.get_default_object(blueprint_generated_class) blueprint_cdo.set_editor_property("Replicates", False)
3. Opearting all assets in given path
import unreal search_path = "/Game" unreal.log("print all file names under " + search_path) asset_register = unreal.AssetRegistryHelpers.get_asset_registry() assets = asset_register.get_assets_by_path(unreal.Name(search_path)) for asset in assets: unreal.log(asset.get_full_name()) text = unreal.NSLOCTEXT("Editor", "Entry", "入口")
4. Support Undo and Redo
We take the changing editor property we mentioned before as an example, you can use ctrl+z to undo it, note that you can check it in Edit->Undo History
import unreal blueprint_generated_class = unreal.load_object(None, "/Game/StaticMeshActor.StaticMeshActor_C") if blueprint_generated_class is None: unreal.log("obj is none") blueprint_cdo = unreal.get_default_object(blueprint_generated_class) with unreal.ScopedEditorTransaction("My Transaction Test") as trans: blueprint_cdo.set_editor_property("Replicates", True)
5. Add a Button Entry for Engine Editor
Note that there is no label text for this button because I use English culture for screenshot, however, I use Chinese culture by default and did not do localization for it.
import unreal @unreal.uclass() class MyEntryScript(unreal.ToolMenuEntryScript): @unreal.ufunction(override=True) def execute(self, context): on_button_clicked() @unreal.ufunction(override=True) def can_execute(self, context) -> bool: return True def on_button_clicked(): unreal.log("Button clicked") def create_menu_widget(): menu = unreal.ToolMenus.get() editor = menu.find_menu(unreal.Name("LevelEditor.MainMenu.Edit")) if not editor: unreal.log("cannot find LevelEditor.MainMenu.Edit") return entry = unreal.ToolMenuEntry() entry.name = "My Entry" entry.set_label(unreal.NSLOCTEXT("Editor", "Python Test Label", "Our Entry")) entry.type = unreal.MultiBlockType.MENU_ENTRY entry.insert_position = unreal.ToolMenuInsert(unreal.Name("Delete"), unreal.ToolMenuInsertType.AFTER) script_object = MyEntryScript() entry.script_object = script_object editor.add_menu_entry(unreal.Name("EditMain"), entry) unreal.log("Add button extension to menubar") create_menu_widget()
6. Logging and Feedback
The unreal object exposes functions that you can use in your code to send log, warning, and error messages through the same messaging system used by all Engine and Editor subsystems. We recommend using this standardized logging framework anytime your script needs to send a message to the user.
- Use unreal.log() for information messages. For your convenience, the Python
print()
function has also been implemented to pass throughunreal.log()
internally. - Use unreal.log_warning() to alert users of potential problems.
- Use unreal.log_error() for severe problems that prevent your script from running as expected.
unreal.log("log") unreal.log_warning("warning") unreal.log_error("error")
Amazing! This blog looks just like my old one! It’s on a totally different topic but it has
pretty much the same page layout and design. Wonderful choice of colors!
I’m glad we have similar aesthetics!