2022-03-18 17:46:08 +01:00
|
|
|
|
.. _doc_making_plugins:
|
|
|
|
|
|
|
|
|
|
Making plugins
|
|
|
|
|
==============
|
|
|
|
|
|
|
|
|
|
About plugins
|
|
|
|
|
~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
|
|
A plugin is a great way to extend the editor with useful tools. It can be made
|
|
|
|
|
entirely with GDScript and standard scenes, without even reloading the editor.
|
|
|
|
|
Unlike modules, you don't need to create C++ code nor recompile the engine.
|
|
|
|
|
While this makes plugins less powerful, there are still many things you can
|
|
|
|
|
do with them. Note that a plugin is similar to any scene you can already
|
|
|
|
|
make, except it is created using a script to add editor functionality.
|
|
|
|
|
|
|
|
|
|
This tutorial will guide you through the creation of two simple plugins so
|
|
|
|
|
you can understand how they work and be able to develop your own. The first
|
|
|
|
|
will be a custom node that you can add to any scene in the project and the
|
|
|
|
|
other will be a custom dock added to the editor.
|
|
|
|
|
|
|
|
|
|
Creating a plugin
|
|
|
|
|
~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
|
|
Before starting, create a new empty project wherever you want. This will serve
|
|
|
|
|
as a base to develop and test the plugins.
|
|
|
|
|
|
|
|
|
|
The first thing you need for the editor to identify a new plugin is to
|
2023-01-12 19:43:03 +01:00
|
|
|
|
create two files: a `plugin.cfg` for configuration and a tool script with the
|
|
|
|
|
functionality. Plugins have a standard path like `addons/plugin_name` inside
|
2022-03-18 17:46:08 +01:00
|
|
|
|
the project folder. Godot provides a dialog for generating those files and
|
|
|
|
|
placing them where they need to be.
|
|
|
|
|
|
2023-01-12 19:43:03 +01:00
|
|
|
|
In the main toolbar, click the `Project` dropdown. Then click
|
|
|
|
|
`Project Settings...`. Go to the `Plugins` tab and then click
|
|
|
|
|
on the `Create` button in the top-right.
|
2022-03-18 17:46:08 +01:00
|
|
|
|
|
|
|
|
|
You will see the dialog appear, like so:
|
|
|
|
|
|
2023-01-12 20:16:00 +01:00
|
|
|
|
![](img/making_plugins-create_plugin_dialog.png)
|
2022-03-18 17:46:08 +01:00
|
|
|
|
|
|
|
|
|
The placeholder text in each field describes how it affects the plugin's
|
|
|
|
|
creation of the files and the config file's values.
|
|
|
|
|
|
2022-09-10 12:15:58 +02:00
|
|
|
|
To continue with the example, use the following values:
|
|
|
|
|
|
2023-01-12 18:31:02 +01:00
|
|
|
|
ini GDScript
|
2022-03-18 17:46:08 +01:00
|
|
|
|
|
2023-01-12 18:31:02 +01:00
|
|
|
|
```
|
2022-03-18 17:46:08 +01:00
|
|
|
|
Plugin Name: My Custom Node
|
|
|
|
|
Subfolder: my_custom_node
|
|
|
|
|
Description: A custom node made to extend the Godot Engine.
|
|
|
|
|
Author: Your Name Here
|
|
|
|
|
Version: 1.0.0
|
|
|
|
|
Language: GDScript
|
|
|
|
|
Script Name: custom_node.gd
|
|
|
|
|
Activate now: No
|
2023-01-12 18:31:02 +01:00
|
|
|
|
```
|
2022-09-10 12:15:58 +02:00
|
|
|
|
|
|
|
|
|
.. warning::
|
|
|
|
|
|
2023-01-12 19:43:03 +01:00
|
|
|
|
Unchecking the `Activate now?` option in C# is always required because,
|
2022-09-10 12:15:58 +02:00
|
|
|
|
like every other C# script, the EditorPlugin script needs to be compiled which
|
|
|
|
|
requires building the project. After building the project the plugin can be
|
2023-01-12 19:43:03 +01:00
|
|
|
|
enabled in the `Plugins` tab of `Project Settings`.
|
2022-09-10 12:15:58 +02:00
|
|
|
|
|
2022-03-18 17:46:08 +01:00
|
|
|
|
You should end up with a directory structure like this:
|
|
|
|
|
|
2023-01-12 20:16:00 +01:00
|
|
|
|
![](img/making_plugins-my_custom_mode_folder.png)
|
2022-03-18 17:46:08 +01:00
|
|
|
|
|
2023-01-12 19:43:03 +01:00
|
|
|
|
`plugin.cfg` is a simple INI file with metadata about your plugin.
|
2022-03-18 17:46:08 +01:00
|
|
|
|
The name and description help people understand what it does.
|
|
|
|
|
Your name helps you get properly credited for your work.
|
|
|
|
|
The version number helps others know if they have an outdated version;
|
|
|
|
|
if you are unsure on how to come up with the version number, check out `Semantic Versioning <https://semver.org/>`_.
|
|
|
|
|
The main script file will instruct Godot what your plugin does in the editor
|
|
|
|
|
once it is active.
|
|
|
|
|
|
|
|
|
|
The script file
|
|
|
|
|
^^^^^^^^^^^^^^^
|
|
|
|
|
|
|
|
|
|
Upon creation of the plugin, the dialog will automatically open the
|
|
|
|
|
EditorPlugin script for you. The script has two requirements that you cannot
|
2023-01-12 19:43:03 +01:00
|
|
|
|
change: it must be a `tool` script, or else it will not load properly in the
|
2023-01-12 19:32:38 +01:00
|
|
|
|
editor, and it must inherit from `EditorPlugin`.
|
2022-03-18 17:46:08 +01:00
|
|
|
|
|
|
|
|
|
.. warning::
|
|
|
|
|
|
|
|
|
|
In addition to the EditorPlugin script, any other GDScript that your plugin uses
|
2023-01-12 19:43:03 +01:00
|
|
|
|
must *also* be a tool. Any GDScript without `tool` imported into the editor
|
2022-03-18 17:46:08 +01:00
|
|
|
|
will act like an empty file!
|
|
|
|
|
|
|
|
|
|
It's important to deal with initialization and clean-up of resources.
|
|
|
|
|
A good practice is to use the virtual function
|
2023-01-12 19:30:47 +01:00
|
|
|
|
`_enter_tree()` to initialize your plugin and
|
|
|
|
|
`_exit_tree()` to clean it up. Thankfully,
|
2022-03-18 17:46:08 +01:00
|
|
|
|
the dialog generates these callbacks for you. Your script should look something
|
|
|
|
|
like this:
|
|
|
|
|
|
|
|
|
|
.. _doc_making_plugins_template_code:
|
|
|
|
|
|
2023-01-12 18:31:02 +01:00
|
|
|
|
gdscript GDScript
|
|
|
|
|
|
|
|
|
|
```
|
2022-03-18 17:46:08 +01:00
|
|
|
|
tool
|
|
|
|
|
extends EditorPlugin
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _enter_tree():
|
|
|
|
|
# Initialization of the plugin goes here.
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _exit_tree():
|
|
|
|
|
# Clean-up of the plugin goes here.
|
|
|
|
|
pass
|
2023-01-12 18:31:02 +01:00
|
|
|
|
```
|
2022-03-18 17:46:08 +01:00
|
|
|
|
|
|
|
|
|
This is a good template to use when creating new plugins.
|
|
|
|
|
|
|
|
|
|
A custom node
|
|
|
|
|
~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
|
|
Sometimes you want a certain behavior in many nodes, such as a custom scene
|
|
|
|
|
or control that can be reused. Instancing is helpful in a lot of cases, but
|
|
|
|
|
sometimes it can be cumbersome, especially if you're using it in many
|
|
|
|
|
projects. A good solution to this is to make a plugin that adds a node with a
|
|
|
|
|
custom behavior.
|
|
|
|
|
|
|
|
|
|
.. warning::
|
|
|
|
|
|
|
|
|
|
Nodes added via an EditorPlugin are "CustomType" nodes. While they work
|
|
|
|
|
with any scripting language, they have fewer features than
|
2023-01-12 19:29:11 +01:00
|
|
|
|
`the Script Class system <doc_gdscript_basics_class_name>`. If you
|
2022-03-18 17:46:08 +01:00
|
|
|
|
are writing GDScript or NativeScript, we recommend using Script Classes instead.
|
|
|
|
|
|
|
|
|
|
To create a new node type, you can use the function
|
2023-01-12 19:30:47 +01:00
|
|
|
|
`add_custom_type()` from the
|
2023-01-12 19:32:38 +01:00
|
|
|
|
`EditorPlugin` class. This function can add new types to the editor
|
2022-03-18 17:46:08 +01:00
|
|
|
|
(nodes or resources). However, before you can create the type, you need a script
|
|
|
|
|
that will act as the logic for the type. While that script doesn't have to use
|
2023-01-12 19:43:03 +01:00
|
|
|
|
the `tool` keyword, it can be added so the script runs in the editor.
|
2022-03-18 17:46:08 +01:00
|
|
|
|
|
|
|
|
|
For this tutorial, we'll create a simple button that prints a message when
|
|
|
|
|
clicked. For that, we'll need a simple script that extends from
|
2023-01-12 19:32:38 +01:00
|
|
|
|
`Button`. It could also extend
|
|
|
|
|
`BaseButton` if you prefer:
|
2022-03-18 17:46:08 +01:00
|
|
|
|
|
2023-01-12 18:31:02 +01:00
|
|
|
|
gdscript GDScript
|
2022-03-18 17:46:08 +01:00
|
|
|
|
|
2023-01-12 18:31:02 +01:00
|
|
|
|
```
|
2022-03-18 17:46:08 +01:00
|
|
|
|
tool
|
|
|
|
|
extends Button
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _enter_tree():
|
|
|
|
|
connect("pressed", self, "clicked")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func clicked():
|
|
|
|
|
print("You clicked me!")
|
2023-01-12 18:31:02 +01:00
|
|
|
|
```
|
2022-03-18 17:46:08 +01:00
|
|
|
|
|
2023-01-12 19:43:03 +01:00
|
|
|
|
That's it for our basic button. You can save this as `my_button.gd` inside the
|
2022-03-18 17:46:08 +01:00
|
|
|
|
plugin folder. You'll also need a 16×16 icon to show in the scene tree. If you
|
|
|
|
|
don't have one, you can grab the default one from the engine and save it in your
|
2023-01-12 20:16:00 +01:00
|
|
|
|
`addons/my_custom_node` folder as `icon.png)`, or use the default Godot logo
|
|
|
|
|
(`preload("res://icon.png)")`). You can also use SVG icons if desired.
|
2022-03-18 17:46:08 +01:00
|
|
|
|
|
2023-01-12 20:16:00 +01:00
|
|
|
|
![](img/making_plugins-custom_node_icon.png)
|
2022-03-18 17:46:08 +01:00
|
|
|
|
|
|
|
|
|
Now, we need to add it as a custom type so it shows on the **Create New Node**
|
2023-01-12 19:43:03 +01:00
|
|
|
|
dialog. For that, change the `custom_node.gd` script to the following:
|
2022-03-18 17:46:08 +01:00
|
|
|
|
|
2023-01-12 18:31:02 +01:00
|
|
|
|
gdscript GDScript
|
2022-03-18 17:46:08 +01:00
|
|
|
|
|
2023-01-12 18:31:02 +01:00
|
|
|
|
```
|
2022-03-18 17:46:08 +01:00
|
|
|
|
tool
|
|
|
|
|
extends EditorPlugin
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _enter_tree():
|
|
|
|
|
# Initialization of the plugin goes here.
|
|
|
|
|
# Add the new type with a name, a parent type, a script and an icon.
|
2023-01-12 20:16:00 +01:00
|
|
|
|
add_custom_type("MyButton", "Button", preload("my_button.gd"), preload("icon.png)"))
|
2022-03-18 17:46:08 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _exit_tree():
|
|
|
|
|
# Clean-up of the plugin goes here.
|
|
|
|
|
# Always remember to remove it from the engine when deactivated.
|
|
|
|
|
remove_custom_type("MyButton")
|
2023-01-12 18:31:02 +01:00
|
|
|
|
```
|
2022-03-18 17:46:08 +01:00
|
|
|
|
|
|
|
|
|
With that done, the plugin should already be available in the plugin list in the
|
|
|
|
|
**Project Settings**, so activate it as explained in `Checking the results`_.
|
|
|
|
|
|
|
|
|
|
Then try it out by adding your new node:
|
|
|
|
|
|
2023-01-12 20:16:00 +01:00
|
|
|
|
![](img/making_plugins-custom_node_create.png)
|
2022-03-18 17:46:08 +01:00
|
|
|
|
|
|
|
|
|
When you add the node, you can see that it already has the script you created
|
|
|
|
|
attached to it. Set a text to the button, save and run the scene. When you
|
|
|
|
|
click the button, you can see some text in the console:
|
|
|
|
|
|
2023-01-12 20:16:00 +01:00
|
|
|
|
![](img/making_plugins-custom_node_console.png)
|
2022-03-18 17:46:08 +01:00
|
|
|
|
|
|
|
|
|
A custom dock
|
|
|
|
|
^^^^^^^^^^^^^
|
|
|
|
|
|
|
|
|
|
Sometimes, you need to extend the editor and add tools that are always available.
|
|
|
|
|
An easy way to do it is to add a new dock with a plugin. Docks are just scenes
|
|
|
|
|
based on Control, so they are created in a way similar to usual GUI scenes.
|
|
|
|
|
|
|
|
|
|
Creating a custom dock is done just like a custom node. Create a new
|
2023-01-12 19:43:03 +01:00
|
|
|
|
`plugin.cfg` file in the `addons/my_custom_dock` folder, then
|
2022-03-18 17:46:08 +01:00
|
|
|
|
add the following content to it:
|
|
|
|
|
|
2023-01-12 18:31:02 +01:00
|
|
|
|
gdscript GDScript
|
2022-03-18 17:46:08 +01:00
|
|
|
|
|
2023-01-12 18:31:02 +01:00
|
|
|
|
```
|
2022-03-18 17:46:08 +01:00
|
|
|
|
[plugin]
|
|
|
|
|
|
|
|
|
|
name="My Custom Dock"
|
|
|
|
|
description="A custom dock made so I can learn how to make plugins."
|
|
|
|
|
author="Your Name Here"
|
|
|
|
|
version="1.0"
|
|
|
|
|
script="custom_dock.gd"
|
2023-01-12 18:31:02 +01:00
|
|
|
|
```
|
2022-03-18 17:46:08 +01:00
|
|
|
|
|
2023-01-12 19:43:03 +01:00
|
|
|
|
Then create the script `custom_dock.gd` in the same folder. Fill it with the
|
2023-01-12 19:29:11 +01:00
|
|
|
|
`template we've seen before <doc_making_plugins_template_code>` to get a
|
2022-03-18 17:46:08 +01:00
|
|
|
|
good start.
|
|
|
|
|
|
|
|
|
|
Since we're trying to add a new custom dock, we need to create the contents of
|
|
|
|
|
the dock. This is nothing more than a standard Godot scene: just create
|
|
|
|
|
a new scene in the editor then edit it.
|
|
|
|
|
|
2023-01-12 19:30:47 +01:00
|
|
|
|
For an editor dock, the root node **must** be a `Control`
|
2022-03-18 17:46:08 +01:00
|
|
|
|
or one of its child classes. For this tutorial, you can create a single button.
|
|
|
|
|
The name of the root node will also be the name that appears on the dock tab,
|
|
|
|
|
so be sure to give it a short and descriptive name.
|
|
|
|
|
Also, don't forget to add some text to your button.
|
|
|
|
|
|
2023-01-12 20:16:00 +01:00
|
|
|
|
![](img/making_plugins-my_custom_dock_scene.png)
|
2022-03-18 17:46:08 +01:00
|
|
|
|
|
2023-01-12 19:43:03 +01:00
|
|
|
|
Save this scene as `my_dock.tscn`. Now, we need to grab the scene we created
|
2022-03-18 17:46:08 +01:00
|
|
|
|
then add it as a dock in the editor. For this, you can rely on the function
|
2023-01-12 19:30:47 +01:00
|
|
|
|
`add_control_to_dock()` from the
|
|
|
|
|
`EditorPlugin` class.
|
2022-03-18 17:46:08 +01:00
|
|
|
|
|
|
|
|
|
You need to select a dock position and define the control to add
|
|
|
|
|
(which is the scene you just created). Don't forget to
|
|
|
|
|
**remove the dock** when the plugin is deactivated.
|
|
|
|
|
The script could look like this:
|
|
|
|
|
|
2023-01-12 18:31:02 +01:00
|
|
|
|
gdscript GDScript
|
2022-03-18 17:46:08 +01:00
|
|
|
|
|
2023-01-12 18:31:02 +01:00
|
|
|
|
```
|
2022-03-18 17:46:08 +01:00
|
|
|
|
tool
|
|
|
|
|
extends EditorPlugin
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# A class member to hold the dock during the plugin life cycle.
|
|
|
|
|
var dock
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _enter_tree():
|
|
|
|
|
# Initialization of the plugin goes here.
|
|
|
|
|
# Load the dock scene and instance it.
|
|
|
|
|
dock = preload("res://addons/my_custom_dock/my_dock.tscn").instance()
|
|
|
|
|
|
|
|
|
|
# Add the loaded scene to the docks.
|
|
|
|
|
add_control_to_dock(DOCK_SLOT_LEFT_UL, dock)
|
|
|
|
|
# Note that LEFT_UL means the left of the editor, upper-left dock.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _exit_tree():
|
|
|
|
|
# Clean-up of the plugin goes here.
|
|
|
|
|
# Remove the dock.
|
|
|
|
|
remove_control_from_docks(dock)
|
|
|
|
|
# Erase the control from the memory.
|
|
|
|
|
dock.free()
|
2023-01-12 18:31:02 +01:00
|
|
|
|
```
|
2022-03-18 17:46:08 +01:00
|
|
|
|
|
|
|
|
|
Note that, while the dock will initially appear at its specified position,
|
|
|
|
|
the user can freely change its position and save the resulting layout.
|
|
|
|
|
|
|
|
|
|
Checking the results
|
|
|
|
|
^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
|
|
|
|
|
It's now time to check the results of your work. Open the **Project
|
|
|
|
|
Settings** and click on the **Plugins** tab. Your plugin should be the only one
|
|
|
|
|
on the list. If it is not showing, click on the **Update** button in the
|
|
|
|
|
top-right corner.
|
|
|
|
|
|
2023-01-12 20:16:00 +01:00
|
|
|
|
![](img/making_plugins-project_settings.png)
|
2022-03-18 17:46:08 +01:00
|
|
|
|
|
|
|
|
|
You can see the plugin is inactive on the **Status** column; click on the status
|
|
|
|
|
to select **Active**. The dock should become visible before you even close
|
|
|
|
|
the settings window. You should now have a custom dock:
|
|
|
|
|
|
2023-01-12 20:16:00 +01:00
|
|
|
|
![](img/making_plugins-custom_dock.png)
|
2022-03-18 17:46:08 +01:00
|
|
|
|
|
|
|
|
|
Going beyond
|
|
|
|
|
~~~~~~~~~~~~
|
|
|
|
|
|
|
|
|
|
Now that you've learned how to make basic plugins, you can extend the editor in
|
|
|
|
|
several ways. Lots of functionality can be added to the editor with GDScript;
|
|
|
|
|
it is a powerful way to create specialized editors without having to delve into
|
|
|
|
|
C++ modules.
|
|
|
|
|
|
|
|
|
|
You can make your own plugins to help yourself and share them in the
|
|
|
|
|
`Asset Library <https://godotengine.org/asset-library/>`_ so that people
|
|
|
|
|
can benefit from your work.
|
2022-09-10 12:15:58 +02:00
|
|
|
|
|
|
|
|
|
.. _doc_making_plugins_autoload:
|
|
|
|
|
|
|
|
|
|
Registering autoloads/singletons in plugins
|
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
|
|
It is possible for editor plugins to automatically register
|
2023-01-12 19:29:11 +01:00
|
|
|
|
`autoloads <doc_singletons_autoload>` when the plugin is enabled.
|
2022-09-10 12:15:58 +02:00
|
|
|
|
This also includes unregistering the autoload when the plugin is disabled.
|
|
|
|
|
|
|
|
|
|
This makes setting up plugins faster for users, as they no longer have to manually
|
|
|
|
|
add autoloads to their project settings if your editor plugin requires the use of
|
|
|
|
|
an autoload.
|
|
|
|
|
|
|
|
|
|
Use the following code to register a singleton from an editor plugin:
|
|
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
|
|
tool
|
|
|
|
|
extends EditorPlugin
|
|
|
|
|
|
|
|
|
|
# Replace this value with a PascalCase autoload name, as per the GDScript style guide.
|
|
|
|
|
const AUTOLOAD_NAME = "SomeAutoload"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _enter_tree():
|
|
|
|
|
# The autoload can be a scene or script file.
|
|
|
|
|
add_autoload_singleton(AUTOLOAD_NAME, "res://addons/my_addon/some_autoload.tscn")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _exit_tree():
|
|
|
|
|
remove_autoload_singleton(AUTOLOAD_NAME)
|