making_plugins.rst 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. .. _doc_making_plugins:
  2. Making plugins
  3. ==============
  4. About plugins
  5. ~~~~~~~~~~~~~
  6. A plugin is a great way to extend the editor with useful tools. It can be made
  7. entirely with GDScript and standard scenes, without even reloading the editor.
  8. Unlike modules, you don't need to create C++ code nor recompile the engine.
  9. While this makes plugins less powerful, there are still many things you can
  10. do with them. Note that a plugin is similar to any scene you can already
  11. make, except it is created using a script to add editor functionality.
  12. This tutorial will guide you through the creation of two simple plugins so
  13. you can understand how they work and be able to develop your own. The first
  14. will be a custom node that you can add to any scene in the project and the
  15. other will be a custom dock added to the editor.
  16. Creating a plugin
  17. ~~~~~~~~~~~~~~~~~
  18. Before starting, create a new empty project wherever you want. This will serve
  19. as a base to develop and test the plugins.
  20. The first thing you need for the editor to identify a new plugin is to
  21. create two files: a ``plugin.cfg`` for configuration and a tool script with the
  22. functionality. Plugins have a standard path like ``addons/plugin_name`` inside
  23. the project folder. Godot provides a dialog for generating those files and
  24. placing them where they need to be.
  25. In the main toolbar, click the ``Project`` dropdown. Then click
  26. ``Project Settings...``. Go to the ``Plugins`` tab and then click
  27. on the ``Create`` button in the top-right.
  28. You will see the dialog appear, like so:
  29. .. image:: img/making_plugins-create_plugin_dialog.png
  30. The placeholder text in each field describes how it affects the plugin's
  31. creation of the files and the config file's values.
  32. To continue with the example, use the following values::
  33. Plugin Name: My Custom Node
  34. Subfolder: my_custom_node
  35. Description: A custom node made to extend the Godot Engine.
  36. Author: Your Name Here
  37. Version: 1.0.0
  38. Language: GDScript
  39. Script Name: custom_node.gd
  40. Activate now: No
  41. You should end up with a directory structure like this:
  42. .. image:: img/making_plugins-my_custom_mode_folder.png
  43. ``plugin.cfg`` is a simple INI file with metadata about your plugin.
  44. The name and description help people understand what it does.
  45. Your name helps you get properly credited for your work.
  46. The version number helps others know if they have an outdated version;
  47. if you are unsure on how to come up with the version number, check out `Semantic Versioning <https://semver.org/>`_.
  48. The main script file will instruct Godot what your plugin does in the editor
  49. once it is active.
  50. The script file
  51. ^^^^^^^^^^^^^^^
  52. Upon creation of the plugin, the dialog will automatically open the
  53. EditorPlugin script for you. The script has two requirements that you cannot
  54. change: it must be a ``tool`` script, or else it will not load properly in the
  55. editor, and it must inherit from :ref:`class_EditorPlugin`.
  56. .. warning::
  57. In addition to the EditorPlugin script, any other GDScript that your plugin uses
  58. must *also* be a tool. Any GDScript without ``tool`` imported into the editor
  59. will act like an empty file!
  60. It's important to deal with initialization and clean-up of resources.
  61. A good practice is to use the virtual function
  62. :ref:`_enter_tree() <class_Node_method__enter_tree>` to initialize your plugin and
  63. :ref:`_exit_tree() <class_Node_method__exit_tree>` to clean it up. Thankfully,
  64. the dialog generates these callbacks for you. Your script should look something
  65. like this:
  66. .. _doc_making_plugins_template_code:
  67. .. tabs::
  68. .. code-tab:: gdscript GDScript
  69. tool
  70. extends EditorPlugin
  71. func _enter_tree():
  72. # Initialization of the plugin goes here.
  73. pass
  74. func _exit_tree():
  75. # Clean-up of the plugin goes here.
  76. pass
  77. .. code-tab:: csharp
  78. #if TOOLS
  79. using Godot;
  80. using System;
  81. [Tool]
  82. public class CustomNode : EditorPlugin
  83. {
  84. public override void _EnterTree()
  85. {
  86. // Initialization of the plugin goes here.
  87. }
  88. public override void _ExitTree()
  89. {
  90. // Clean-up of the plugin goes here.
  91. }
  92. }
  93. #endif
  94. This is a good template to use when creating new plugins.
  95. A custom node
  96. ~~~~~~~~~~~~~
  97. Sometimes you want a certain behavior in many nodes, such as a custom scene
  98. or control that can be reused. Instancing is helpful in a lot of cases, but
  99. sometimes it can be cumbersome, especially if you're using it in many
  100. projects. A good solution to this is to make a plugin that adds a node with a
  101. custom behavior.
  102. .. warning::
  103. Nodes added via an EditorPlugin are "CustomType" nodes. While they work
  104. with any scripting language, they have fewer features than
  105. :ref:`the Script Class system <doc_scripting_continued_class_name>`. If you
  106. are writing GDScript or NativeScript, we recommend using Script Classes instead.
  107. To create a new node type, you can use the function
  108. :ref:`add_custom_type() <class_EditorPlugin_method_add_custom_type>` from the
  109. :ref:`class_EditorPlugin` class. This function can add new types to the editor
  110. (nodes or resources). However, before you can create the type, you need a script
  111. that will act as the logic for the type. While that script doesn't have to use
  112. the ``tool`` keyword, it can be added so the script runs in the editor.
  113. For this tutorial, we'll create a simple button that prints a message when
  114. clicked. For that, we'll need a simple script that extends from
  115. :ref:`class_Button`. It could also extend
  116. :ref:`class_BaseButton` if you prefer:
  117. .. tabs::
  118. .. code-tab:: gdscript GDScript
  119. tool
  120. extends Button
  121. func _enter_tree():
  122. connect("pressed", self, "clicked")
  123. func clicked():
  124. print("You clicked me!")
  125. .. code-tab:: csharp
  126. using Godot;
  127. using System;
  128. [Tool]
  129. public class MyButton : Button
  130. {
  131. public override void _EnterTree()
  132. {
  133. Connect("pressed", this, "clicked");
  134. }
  135. public void clicked()
  136. {
  137. GD.Print("You clicked me!");
  138. }
  139. }
  140. That's it for our basic button. You can save this as ``my_button.gd`` inside the
  141. plugin folder. You'll also need a 16×16 icon to show in the scene tree. If you
  142. don't have one, you can grab the default one from the engine and save it in your
  143. `addons/my_custom_node` folder as `icon.png`, or use the default Godot logo
  144. (`preload("res://icon.png")`). You can also use SVG icons if desired.
  145. .. image:: img/making_plugins-custom_node_icon.png
  146. Now, we need to add it as a custom type so it shows on the **Create New Node**
  147. dialog. For that, change the ``custom_node.gd`` script to the following:
  148. .. tabs::
  149. .. code-tab:: gdscript GDScript
  150. tool
  151. extends EditorPlugin
  152. func _enter_tree():
  153. # Initialization of the plugin goes here.
  154. # Add the new type with a name, a parent type, a script and an icon.
  155. add_custom_type("MyButton", "Button", preload("my_button.gd"), preload("icon.png"))
  156. func _exit_tree():
  157. # Clean-up of the plugin goes here.
  158. # Always remember to remove it from the engine when deactivated.
  159. remove_custom_type("MyButton")
  160. .. code-tab:: csharp
  161. #if TOOLS
  162. using Godot;
  163. using System;
  164. [Tool]
  165. public class CustomNode : EditorPlugin
  166. {
  167. public override void _EnterTree()
  168. {
  169. // Initialization of the plugin goes here.
  170. // Add the new type with a name, a parent type, a script and an icon.
  171. var script = GD.Load<Script>("MyButton.cs");
  172. var texture = GD.Load<Texture>("icon.png");
  173. AddCustomType("MyButton", "Button", script, texture);
  174. }
  175. public override void _ExitTree()
  176. {
  177. // Clean-up of the plugin goes here.
  178. // Always remember to remove it from the engine when deactivated.
  179. RemoveCustomType("MyButton");
  180. }
  181. }
  182. #endif
  183. With that done, the plugin should already be available in the plugin list in the
  184. **Project Settings**, so activate it as explained in `Checking the results`_.
  185. Then try it out by adding your new node:
  186. .. image:: img/making_plugins-custom_node_create.png
  187. When you add the node, you can see that it already has the script you created
  188. attached to it. Set a text to the button, save and run the scene. When you
  189. click the button, you can see some text in the console:
  190. .. image:: img/making_plugins-custom_node_console.png
  191. A custom dock
  192. ^^^^^^^^^^^^^
  193. Sometimes, you need to extend the editor and add tools that are always available.
  194. An easy way to do it is to add a new dock with a plugin. Docks are just scenes
  195. based on Control, so they are created in a way similar to usual GUI scenes.
  196. Creating a custom dock is done just like a custom node. Create a new
  197. ``plugin.cfg`` file in the ``addons/my_custom_dock`` folder, then
  198. add the following content to it:
  199. .. tabs::
  200. .. code-tab:: gdscript GDScript
  201. [plugin]
  202. name="My Custom Dock"
  203. description="A custom dock made so I can learn how to make plugins."
  204. author="Your Name Here"
  205. version="1.0"
  206. script="custom_dock.gd"
  207. .. code-tab:: csharp
  208. [plugin]
  209. name="My Custom Dock"
  210. description="A custom dock made so I can learn how to make plugins."
  211. author="Your Name Here"
  212. version="1.0"
  213. script="CustomDock.cs"
  214. Then create the script ``custom_dock.gd`` in the same folder. Fill it with the
  215. :ref:`template we've seen before <doc_making_plugins_template_code>` to get a
  216. good start.
  217. Since we're trying to add a new custom dock, we need to create the contents of
  218. the dock. This is nothing more than a standard Godot scene: just create
  219. a new scene in the editor then edit it.
  220. For an editor dock, the root node **must** be a :ref:`Control <class_Control>`
  221. or one of its child classes. For this tutorial, you can create a single button.
  222. The name of the root node will also be the name that appears on the dock tab,
  223. so be sure to give it a short and descriptive name.
  224. Also, don't forget to add some text to your button.
  225. .. image:: img/making_plugins-my_custom_dock_scene.png
  226. Save this scene as ``my_dock.tscn``. Now, we need to grab the scene we created
  227. then add it as a dock in the editor. For this, you can rely on the function
  228. :ref:`add_control_to_dock() <class_EditorPlugin_method_add_control_to_dock>` from the
  229. :ref:`EditorPlugin <class_EditorPlugin>` class.
  230. You need to select a dock position and define the control to add
  231. (which is the scene you just created). Don't forget to
  232. **remove the dock** when the plugin is deactivated.
  233. The script could look like this:
  234. .. tabs::
  235. .. code-tab:: gdscript GDScript
  236. tool
  237. extends EditorPlugin
  238. # A class member to hold the dock during the plugin life cycle.
  239. var dock
  240. func _enter_tree():
  241. # Initialization of the plugin goes here.
  242. # Load the dock scene and instance it.
  243. dock = preload("res://addons/my_custom_dock/my_dock.tscn").instance()
  244. # Add the loaded scene to the docks.
  245. add_control_to_dock(DOCK_SLOT_LEFT_UL, dock)
  246. # Note that LEFT_UL means the left of the editor, upper-left dock.
  247. func _exit_tree():
  248. # Clean-up of the plugin goes here.
  249. # Remove the dock.
  250. remove_control_from_docks(dock)
  251. # Erase the control from the memory.
  252. dock.free()
  253. .. code-tab:: csharp
  254. #if TOOLS
  255. using Godot;
  256. using System;
  257. [Tool]
  258. public class CustomDock : EditorPlugin
  259. {
  260. Control dock;
  261. public override void _EnterTree()
  262. {
  263. dock = (Control)GD.Load<PackedScene>("addons/my_custom_dock/my_dock.tscn").Instance();
  264. AddControlToDock(DockSlot.LeftUl, dock);
  265. }
  266. public override void _ExitTree()
  267. {
  268. // Clean-up of the plugin goes here.
  269. // Remove the dock.
  270. RemoveControlFromDocks(dock);
  271. // Erase the control from the memory.
  272. dock.Free();
  273. }
  274. }
  275. #endif
  276. Note that, while the dock will initially appear at its specified position,
  277. the user can freely change its position and save the resulting layout.
  278. Checking the results
  279. ^^^^^^^^^^^^^^^^^^^^
  280. It's now time to check the results of your work. Open the **Project
  281. Settings** and click on the **Plugins** tab. Your plugin should be the only one
  282. on the list. If it is not showing, click on the **Update** button in the
  283. top-right corner.
  284. .. image:: img/making_plugins-project_settings.png
  285. You can see the plugin is inactive on the **Status** column; click on the status
  286. to select **Active**. The dock should become visible before you even close
  287. the settings window. You should now have a custom dock:
  288. .. image:: img/making_plugins-custom_dock.png
  289. Going beyond
  290. ~~~~~~~~~~~~
  291. Now that you've learned how to make basic plugins, you can extend the editor in
  292. several ways. Lots of functionality can be added to the editor with GDScript;
  293. it is a powerful way to create specialized editors without having to delve into
  294. C++ modules.
  295. You can make your own plugins to help yourself and share them in the
  296. `Asset Library <https://godotengine.org/asset-library/>`_ so that people
  297. can benefit from your work.