This page documents the EditorPlugin base class, its virtual method contract, how plugins are registered and managed within the editor, and the lifecycle from loading through unloading. This covers both built-in C++ plugins and GDScript/GDExtension addon plugins.
For the public API available to plugins for querying and manipulating the editor, see EditorInterface. For editor-level state such as scene history and custom type registration, see EditorData. For the central orchestrator that manages all plugins, see EditorNode.
EditorPlugin is the extension point that allows any feature to integrate into the Godot editor. All built-in editor tools — the 2D editor, 3D editor, animation editor, asset library, debugger, and others — are implemented as EditorPlugin subclasses. User addon plugins follow the same mechanism.
Key source files:
| File | Role |
|---|---|
| editor/plugins/editor_plugin.h | EditorPlugin class declaration |
| editor/plugins/editor_plugin_list.h | EditorPluginList for input forwarding |
| editor/editor_node.h | Plugin registry, enable/disable, init callbacks |
| editor/editor_data.h | Plugin state delegation, plugin querying by object |
| editor/editor_interface.h | API surface exposed to plugins |
EditorPlugin inherits Node and is registered via ClassDB. It lives in the scene tree as a child of EditorNode.
Diagram: Core relationships between plugin-related classes
Sources: editor/plugins/editor_plugin.h editor/editor_node.h editor/editor_data.h
The following table lists all virtual methods that plugins override to participate in editor operations. All are optional unless noted otherwise.
| Virtual Method | Purpose |
|---|---|
_get_plugin_name() | Returns the name shown in the editor UI |
_get_plugin_icon() | Returns the icon texture for the plugin |
_has_main_screen() | Return true to add a main screen tab (next to 2D/3D/Script) |
_make_visible(visible) | Called when the plugin's main screen is shown or hidden |
| Virtual Method | Purpose |
|---|---|
_handles(object) | Return true if this plugin should edit the given object |
_edit(object) | Begin editing the given object; object may be null to clear |
_clear() | Reset the plugin to an empty editing state |
| Virtual Method | Purpose |
|---|---|
_get_state() | Return a Dictionary of scene-specific state (saved per .editstate file) |
_set_state(state) | Restore scene-specific state |
_get_window_layout(config) | Write global layout to a ConfigFile |
_set_window_layout(config) | Read global layout from a ConfigFile |
_get_unsaved_status(for_scene) | Return a non-empty string if the plugin has unsaved changes |
| Virtual Method | Return | Purpose |
|---|---|---|
_apply_changes() | void | Called before save/tab switch; flush pending state |
_save_external_data() | void | Called when editor saves; write plugin-owned files |
_build() | bool | Called before project run; return false to abort |
_enable_plugin() | void | Called when the plugin is enabled via Project Settings |
_disable_plugin() | void | Called when the plugin is disabled via Project Settings |
| Virtual Method | Return | Purpose |
|---|---|---|
_forward_canvas_gui_input(event) | bool | Intercept 2D viewport input; return true to consume |
_forward_3d_gui_input(camera, event) | AfterGUIInput | Intercept 3D viewport input |
_forward_canvas_draw_over_viewport(control) | void | Draw over the 2D viewport overlay |
_forward_3d_draw_over_viewport(control) | void | Draw over the 3D viewport overlay |
_forward_canvas_force_draw_over_viewport(control) | void | Draw over everything in 2D (requires set_force_draw_over_forwarding_enabled()) |
_forward_3d_force_draw_over_viewport(control) | void | Draw over everything in 3D |
The AfterGUIInput enum values are:
AFTER_GUI_INPUT_PASS — forward the event to the next pluginAFTER_GUI_INPUT_STOP — consume the eventAFTER_GUI_INPUT_CUSTOM — custom handlingSources: doc/classes/EditorPlugin.xml
Diagram: Plugin registration and object routing
Sources: editor/editor_node.cpp editor/editor_data.cpp258-278
Built-in plugins are instantiated in C++ during EditorNode's constructor. They are added via EditorNode::add_editor_plugin(), which delegates to EditorData::add_editor_plugin():
EditorNode::add_editor_plugin(plugin, config_changed)
-> EditorData::add_editor_plugin(plugin)
-> editor_plugins.push_back(plugin)
editor/editor_node.h776-777 declares the static methods:
GDExtension plugins register via a separate map in EditorData:
EditorNode::add_extension_editor_plugin(class_name)
-> EditorData::add_extension_editor_plugin(class_name, plugin)
-> extension_editor_plugins.insert(class_name, plugin)
editor/editor_data.h129-130 stores these in a HashMap<StringName, EditorPlugin *> extension_editor_plugins.
Addon plugins are GDScript (or GDExtension) scripts located in res://addons/<addon_name>/. They are declared via a plugin.cfg file and enabled/disabled from Project > Project Settings > Plugins.
Diagram: Addon plugin enable flow
Relevant members in EditorNode:
| Member | Type | Role |
|---|---|---|
addon_name_to_plugin | HashMap<String, EditorPlugin *> | Maps addon path to live instance |
pending_addons | LocalVector<String> | Addons waiting to be initialized |
_initializing_plugins | bool | Set during first-time plugin loading |
On disable, EditorNode::_remove_plugin_from_enabled() is called, which calls _disable_plugin() on the plugin, removes it from the scene tree, and updates the project configuration.
The method init_plugins() (editor/editor_node.h736) is called after the editor UI is ready to initialize all pending addons. The callback _on_plugin_ready() handles the deferred instantiation of script-based plugins.
EditorData holds the canonical Vector<EditorPlugin *> editor_plugins (editor/editor_data.h129) and provides the primary dispatch functions used by EditorNode.
Diagram: EditorData dispatch to plugins
Sources: editor/editor_data.cpp258-414
get_handling_main_editor() iterates plugins in reverse order so that user-created plugins have priority over built-in ones:
EditorPluginList (editor/plugins/editor_plugin_list.h) groups plugins that participate in viewport input forwarding. EditorNode maintains three such lists:
| List | Member | Purpose |
|---|---|---|
editor_plugins_over | EditorPluginList * | Plugins drawn over the active viewport (normal priority) |
editor_plugins_force_over | EditorPluginList * | Plugins always drawn over the viewport |
editor_plugins_force_input_forwarding | EditorPluginList * | Plugins that always receive input events |
A plugin can opt into the always-forwarding list by calling:
set_input_event_forwarding_always_enabled() — always receive inputset_force_draw_over_forwarding_enabled() — always have draw-over calledPlugins can attach UI to several predefined locations using these non-virtual methods:
| Method | Effect |
|---|---|
add_control_to_dock(slot, control, shortcut) | Add a panel to one of 8 dock slots (DOCK_SLOT_LEFT_UL, etc.) |
add_control_to_bottom_panel(control, title, shortcut) | Add a tab to the bottom panel (Output, Debugger, etc.) |
add_control_to_container(container, control) | Add a control to a named editor container |
add_tool_menu_item(name, callable) | Add an entry under the Project > Tools menu |
add_tool_submenu_item(name, submenu) | Add a submenu under Project > Tools |
The CustomControlContainer enum values used with add_control_to_container():
| Constant | Location |
|---|---|
CONTAINER_TOOLBAR | Main toolbar |
CONTAINER_SPATIAL_EDITOR_MENU | 3D editor top menu |
CONTAINER_SPATIAL_EDITOR_SIDE_LEFT | 3D editor left side |
CONTAINER_SPATIAL_EDITOR_SIDE_RIGHT | 3D editor right side |
CONTAINER_SPATIAL_EDITOR_BOTTOM | 3D editor bottom |
CONTAINER_CANVAS_EDITOR_MENU | 2D editor top menu |
CONTAINER_CANVAS_EDITOR_SIDE_LEFT | 2D editor left side |
CONTAINER_CANVAS_EDITOR_SIDE_RIGHT | 2D editor right side |
CONTAINER_CANVAS_EDITOR_BOTTOM | 2D editor bottom |
CONTAINER_INSPECTOR_BOTTOM | Below the inspector |
CONTAINER_PROJECT_SETTING_TAB_LEFT | Project Settings left tab |
CONTAINER_PROJECT_SETTING_TAB_RIGHT | Project Settings right tab |
Sources: doc/classes/EditorPlugin.xml
EditorPlugin acts as a host for specialized extension points. These sub-plugins do not inherit EditorPlugin directly; they use their own base classes.
| Method | Sub-plugin Type | Purpose |
|---|---|---|
add_inspector_plugin(plugin) | EditorInspectorPlugin | Custom inspector rows for properties |
add_import_plugin(importer) | EditorImportPlugin | Custom asset importers |
add_export_plugin(plugin) | EditorExportPlugin | Custom export behavior |
add_gizmo_plugin(plugin) | EditorNode3DGizmoPlugin | Custom 3D viewport gizmos |
add_scene_format_importer_plugin(p) | EditorSceneFormatImporter | Custom scene file parsers |
add_scene_post_import_plugin(p) | EditorScenePostImportPlugin | Post-processing of imported scenes |
add_translation_parser_plugin(p) | EditorTranslationParserPlugin | Custom translation file parsers |
add_debugger_plugin(script) | EditorDebuggerPlugin | Panels in the debugger tab |
add_resource_conversion_plugin(p) | EditorResourceConversionPlugin | Resource type conversions |
All registrations must be balanced with the corresponding remove_* call in _disable_plugin() to avoid resource leaks.
Plugins can register custom node and resource types that appear in the Create Node and Create Resource dialogs:
EditorPlugin.add_custom_type(type_name, base_class, script, icon)
-> EditorData.add_custom_type(type, inherits, script, icon)
-> custom_types[inherits].push_back(CustomType{...})
Custom types are stored in EditorData::custom_types as HashMap<String, Vector<CustomType>> keyed by the base class name. The CustomType struct holds the name, Ref<Script>, and Ref<Texture2D> icon.
Diagram: Plugin state save and restore during scene switching
Sources: editor/editor_data.cpp314-381
For C++ code that needs to run during editor startup but outside of EditorNode's constructor, EditorNode provides static callback registration:
These are stored in a fixed-size array plugin_init_callbacks[MAX_INIT_CALLBACKS] (limit of 128) and invoked during init_plugins(). This is used by built-in modules and platform-specific code to register their editor plugins without modifying EditorNode directly.
Similarly, EditorBuildCallback callbacks registered via add_build_callback() are invoked before project runs, analogous to _build().
Refresh this wiki
This wiki was recently refreshed. Please wait 3 days to refresh again.