├── .gitignore
├── MyPlugin
├── Content
│ └── Python
│ │ ├── init_unreal.py
│ │ └── my_module.py
├── MyPlugin.uplugin
└── Resources
│ └── icon128.png
├── README.md
└── requirements.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | pip-wheel-metadata/
24 | share/python-wheels/
25 | *.egg-info/
26 | .installed.cfg
27 | *.egg
28 | MANIFEST
29 |
30 | # PyInstaller
31 | # Usually these files are written by a python script from a template
32 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
33 | *.manifest
34 | *.spec
35 |
36 | # Installer logs
37 | pip-log.txt
38 | pip-delete-this-directory.txt
39 |
40 | # Unit test / coverage reports
41 | htmlcov/
42 | .tox/
43 | .nox/
44 | .coverage
45 | .coverage.*
46 | .cache
47 | nosetests.xml
48 | coverage.xml
49 | *.cover
50 | *.py,cover
51 | .hypothesis/
52 | .pytest_cache/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | target/
76 |
77 | # Jupyter Notebook
78 | .ipynb_checkpoints
79 |
80 | # IPython
81 | profile_default/
82 | ipython_config.py
83 |
84 | # pyenv
85 | .python-version
86 |
87 | # pipenv
88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
91 | # install all needed dependencies.
92 | #Pipfile.lock
93 |
94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
95 | __pypackages__/
96 |
97 | # Celery stuff
98 | celerybeat-schedule
99 | celerybeat.pid
100 |
101 | # SageMath parsed files
102 | *.sage.py
103 |
104 | # Environments
105 | .env
106 | .venv
107 | env/
108 | venv/
109 | ENV/
110 | env.bak/
111 | venv.bak/
112 |
113 | # Spyder project settings
114 | .spyderproject
115 | .spyproject
116 |
117 | # Rope project settings
118 | .ropeproject
119 |
120 | # mkdocs documentation
121 | /site
122 |
123 | # mypy
124 | .mypy_cache/
125 | .dmypy.json
126 | dmypy.json
127 |
128 | # Pyre type checker
129 | .pyre/
130 |
--------------------------------------------------------------------------------
/MyPlugin/Content/Python/init_unreal.py:
--------------------------------------------------------------------------------
1 | # code in init_unreal.py wil run on startup if the plugin is enabled
2 | import unreal
3 |
4 |
5 | section_name = 'Plugins'
6 | se_command = 'import my_module;w = my_module.show()' # todo replace with your code
7 | label = 'My Plugin'
8 | tooltip = "my tooltip"
9 |
10 |
11 | def create_script_editor_button():
12 | """Add a tool button to the tool bar"""
13 | menus = unreal.ToolMenus.get()
14 | level_menu_bar = menus.find_menu('LevelEditor.LevelEditorToolBar.PlayToolBar')
15 | level_menu_bar.add_section(section_name=section_name, label=section_name)
16 |
17 | entry = unreal.ToolMenuEntry(type=unreal.MultiBlockType.TOOL_BAR_BUTTON)
18 | entry.set_label(label)
19 | entry.set_tool_tip(tooltip)
20 | entry.set_icon('EditorStyle', 'DebugConsole.Icon')
21 | entry.set_string_command(
22 | type=unreal.ToolMenuStringCommandType.PYTHON,
23 | custom_type=unreal.Name(''), # not sure what this is
24 | string=se_command
25 | )
26 | level_menu_bar.add_menu_entry(section_name, entry)
27 | menus.refresh_all_widgets()
28 |
29 |
30 | def add_cmd_to_menu(label=None, command=None, tooltip=None, icon=None):
31 | unreal_menus = unreal.ToolMenus.get()
32 | parent_menu = unreal_menus.find_menu("LevelEditor.MainMenu.Tools")
33 |
34 | # name kwargs needs to be unique! if not set, it's autogenerated
35 | entry = unreal.ToolMenuEntry(
36 | type=unreal.MultiBlockType.MENU_ENTRY,
37 | insert_position=unreal.ToolMenuInsert("", unreal.ToolMenuInsertType.FIRST),
38 | )
39 | if label:
40 | entry.set_label(label)
41 | if command:
42 | entry.set_string_command(
43 | type=unreal.ToolMenuStringCommandType.PYTHON,
44 | string=command,
45 | custom_type=unreal.Name("_placeholder_"),
46 | )
47 | if tooltip:
48 | entry.set_tool_tip(tooltip)
49 | if icon:
50 | entry.set_icon(icon)
51 |
52 | parent_menu.add_menu_entry("Configuration", entry)
53 |
54 |
55 | # create_script_editor_button() ## uncomment to add a button to the toolbar to launch your tool
56 | add_cmd_to_menu(label=label, command=se_command, tooltip=tooltip)
57 | print("My plugin is enabled")
58 |
--------------------------------------------------------------------------------
/MyPlugin/Content/Python/my_module.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from PySide6.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QVBoxLayout
3 |
4 |
5 | class HelloWorldWidget(QWidget):
6 | def __init__(self):
7 | super().__init__()
8 | self.label = QLabel('Hello')
9 | self.button = QPushButton('OK')
10 | self.button.clicked.connect(self.print_hello)
11 | layout = QVBoxLayout()
12 | layout.addWidget(self.label)
13 | layout.addWidget(self.button)
14 | self.setLayout(layout)
15 |
16 | def print_hello(self):
17 | print('Hello')
18 |
19 |
20 | def show():
21 | widget = HelloWorldWidget()
22 | widget.show()
23 | return widget
24 |
--------------------------------------------------------------------------------
/MyPlugin/MyPlugin.uplugin:
--------------------------------------------------------------------------------
1 | {
2 | "FileVersion": 3,
3 | "Version": 1,
4 | "VersionName": "0.1",
5 | "FriendlyName": "My Plugin",
6 | "Description": "A template for your Unreal Python plugin",
7 | "Category": "tool",
8 | "CreatedBy": "Hannes",
9 | "CreatedByURL": "",
10 | "DocsURL": "",
11 | "MarketplaceURL": "",
12 | "SupportURL": "",
13 | "CanContainContent": true,
14 | "IsBetaVersion": true,
15 | "IsExperimentalVersion": true,
16 | "Installed": false,
17 | "Plugins": [
18 | {
19 | "Name": "PythonScriptPlugin",
20 | "Enabled": true
21 | }
22 | ]
23 | }
--------------------------------------------------------------------------------
/MyPlugin/Resources/icon128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hannesdelbeke/unreal-python-plugin-template/612145179217f3b7c7a5c848be98a29c8b4038f3/MyPlugin/Resources/icon128.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Unreal Python plugin template
2 | A minimalism template for pure Python plugins in Unreal.
3 | Example repos using this template:
4 | - [unrealScriptEditor-plugin](https://github.com/hannesdelbeke/unrealScriptEditor-plugin)
5 | - [texture-browser-unreal-plugin](https://github.com/hannesdelbeke/texture-browser-unreal-plugin)
6 | - [unreal-qt-plugin](https://github.com/hannesdelbeke/unreal-qt-plugin)
7 | - [plugget-unreal-plugin](https://github.com/plugget/plugget-unreal-plugin)
8 |
9 |
10 | ### Content
11 | ```
12 | 📂 MyPlugin
13 | ├── 📂 Content
14 | │ └── 📂 Python
15 | │ └── 📄 init_unreal.py
16 | ├── 📂 Resources
17 | │ └── 🖼️ icon128.png
18 | └── 📄 MyPlugin.uplugin
19 | 📄 .gitignore
20 | 📄 README.md
21 | 📄 requirements.txt
22 | ```
23 |
24 | ### Info
25 | - `MyPlugin` rename the folder to your plugin name. Unreal's naming convention uses PascalCase.
26 | - `MyPlugin.uplugin` Rename this file to your plugin name, and open it with a text editor & edit the content.
27 | - `.gitignore` is setup to prevent unneeded python files from being commit to your git-repo.
28 | - `requirements.txt` Add your pip/pypi dependencies to this file, delete it if not used.
29 | - `README.md`: include an image & description, so people see what's your plugin about.
30 | - `Python` This folder is added to the PYTHONPATH, put the modules you want to import in here
31 |
32 | # Installation
33 |
34 | ### Manual install
35 | 1. save the plugin in your Unreal plugins folder
36 | 2. pip install the Python dependencies from `requirements.txt` to Unreal's site packages folder
37 | (This can be too technical for some people)
38 | 3. enable the plugin in Unreal, and restart Unreal
39 |
40 | ### (OPTIONAL) Add Plugget install support
41 | To support 1-click install & automatically install all dependencies in the `requirements.txt` file, you can add [plugget](https://github.com/hannesdelbeke/plugget) support.
42 | It's a bit more work for you, the developer. But it removes the technical steps for the end user.
43 |
44 | 1. Upload your plugin to a repo. ([example repo](https://github.com/hannesdelbeke/unreal-python-plugin-template))
45 | 2. Create a plugget manifest ([sample manifest](https://github.com/plugget/plugget-pkgs/blob/main/unreal/hello-world-template/latest.json)) that points to your repo,
46 | 3. Make a PR in [plugget-pkgs](https://github.com/hannesdelbeke/plugget-pkgs) to merge it in the public Plugget database.
47 | 4. Add the plugget-install instructions to your README:
48 | ```
49 | Installation with plugget automatically installs all dependencies.
50 | 1. Install the [plugget Qt Unreal plugin](https://github.com/plugget/plugget-unreal-plugin)
51 | 2. Install the package:
52 | - go to the menu `Edit > Plugget Packages` to open the package manager
53 | - search & install `unreal-script-editor` <=========== EDIT THIS TEXT ⚠️
54 | ```
55 |
56 |
57 | example of a more advanced plugin made from this template, and installable through plugget
58 |
59 | - [repo](https://github.com/hannesdelbeke/unreal-plugin-python-script-editor)
60 | - [plugget manifest](https://github.com/plugget/plugget-pkgs/blob/main/unreal/python-script-editor/latest.json)
61 | - plugget package name `unreal-script-editor`
62 |
63 |
64 |
65 | ### Community
66 | - unreal forum [thread](https://forums.unrealengine.com/t/made-a-python-plugin-template/1089878)
67 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | unreal-qt
2 |
--------------------------------------------------------------------------------