diff options
-rw-r--r-- | core/extension/gdextension.cpp | 22 | ||||
-rw-r--r-- | core/extension/gdextension.h | 24 | ||||
-rw-r--r-- | core/extension/gdextension_interface.cpp | 16 | ||||
-rw-r--r-- | core/extension/gdextension_interface.h | 20 | ||||
-rw-r--r-- | editor/editor_data.cpp | 18 | ||||
-rw-r--r-- | editor/editor_data.h | 6 | ||||
-rw-r--r-- | editor/editor_interface.h | 4 | ||||
-rw-r--r-- | editor/editor_node.cpp | 30 | ||||
-rw-r--r-- | editor/editor_node.h | 3 |
9 files changed, 143 insertions, 0 deletions
diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp index 0cbcf58882..8bdea01ae6 100644 --- a/core/extension/gdextension.cpp +++ b/core/extension/gdextension.cpp @@ -678,3 +678,25 @@ String GDExtensionResourceLoader::get_resource_type(const String &p_path) const } return ""; } + +#ifdef TOOLS_ENABLED +Vector<StringName> GDExtensionEditorPlugins::extension_classes; +GDExtensionEditorPlugins::EditorPluginRegisterFunc GDExtensionEditorPlugins::editor_node_add_plugin = nullptr; +GDExtensionEditorPlugins::EditorPluginRegisterFunc GDExtensionEditorPlugins::editor_node_remove_plugin = nullptr; + +void GDExtensionEditorPlugins::add_extension_class(const StringName &p_class_name) { + if (editor_node_add_plugin) { + editor_node_add_plugin(p_class_name); + } else { + extension_classes.push_back(p_class_name); + } +} + +void GDExtensionEditorPlugins::remove_extension_class(const StringName &p_class_name) { + if (editor_node_remove_plugin) { + editor_node_remove_plugin(p_class_name); + } else { + extension_classes.erase(p_class_name); + } +} +#endif // TOOLS_ENABLED diff --git a/core/extension/gdextension.h b/core/extension/gdextension.h index 95811820cf..49f1cf1d8e 100644 --- a/core/extension/gdextension.h +++ b/core/extension/gdextension.h @@ -107,4 +107,28 @@ public: virtual String get_resource_type(const String &p_path) const; }; +#ifdef TOOLS_ENABLED +class GDExtensionEditorPlugins { +private: + static Vector<StringName> extension_classes; + +protected: + friend class EditorNode; + + // Since this in core, we can't directly reference EditorNode, so it will + // set these function pointers in its constructor. + typedef void (*EditorPluginRegisterFunc)(const StringName &p_class_name); + static EditorPluginRegisterFunc editor_node_add_plugin; + static EditorPluginRegisterFunc editor_node_remove_plugin; + +public: + static void add_extension_class(const StringName &p_class_name); + static void remove_extension_class(const StringName &p_class_name); + + static const Vector<StringName> &get_extension_classes() { + return extension_classes; + } +}; +#endif // TOOLS_ENABLED + #endif // GDEXTENSION_H diff --git a/core/extension/gdextension_interface.cpp b/core/extension/gdextension_interface.cpp index 12ef1772e3..21d34b6e0c 100644 --- a/core/extension/gdextension_interface.cpp +++ b/core/extension/gdextension_interface.cpp @@ -1071,6 +1071,20 @@ static void *gdextension_classdb_get_class_tag(GDExtensionConstStringNamePtr p_c return class_info ? class_info->class_ptr : nullptr; } +static void gdextension_editor_add_plugin(GDExtensionConstStringNamePtr p_classname) { +#ifdef TOOLS_ENABLED + const StringName classname = *reinterpret_cast<const StringName *>(p_classname); + GDExtensionEditorPlugins::add_extension_class(classname); +#endif +} + +static void gdextension_editor_remove_plugin(GDExtensionConstStringNamePtr p_classname) { +#ifdef TOOLS_ENABLED + const StringName classname = *reinterpret_cast<const StringName *>(p_classname); + GDExtensionEditorPlugins::remove_extension_class(classname); +#endif +} + #define REGISTER_INTERFACE_FUNC(m_name) GDExtension::register_interface_function(#m_name, (GDExtensionInterfaceFunctionPtr)&gdextension_##m_name) void gdextension_setup_interface() { @@ -1199,6 +1213,8 @@ void gdextension_setup_interface() { REGISTER_INTERFACE_FUNC(classdb_construct_object); REGISTER_INTERFACE_FUNC(classdb_get_method_bind); REGISTER_INTERFACE_FUNC(classdb_get_class_tag); + REGISTER_INTERFACE_FUNC(editor_add_plugin); + REGISTER_INTERFACE_FUNC(editor_remove_plugin); } #undef REGISTER_INTERFACE_FUNCTION diff --git a/core/extension/gdextension_interface.h b/core/extension/gdextension_interface.h index a5ea3918df..3aa41f28da 100644 --- a/core/extension/gdextension_interface.h +++ b/core/extension/gdextension_interface.h @@ -2141,6 +2141,26 @@ typedef void (*GDExtensionInterfaceClassdbUnregisterExtensionClass)(GDExtensionC */ typedef void (*GDExtensionInterfaceGetLibraryPath)(GDExtensionClassLibraryPtr p_library, GDExtensionUninitializedStringPtr r_path); +/** + * @name editor_add_plugin + * + * Adds an editor plugin. + * + * It's safe to call during initialization. + * + * @param p_class_name A pointer to a StringName with the name of a class (descending from EditorPlugin) which is already registered with ClassDB. + */ +typedef void (*GDExtensionInterfaceEditorAddPlugin)(GDExtensionConstStringNamePtr p_class_name); + +/** + * @name editor_remove_plugin + * + * Removes an editor plugin. + * + * @param p_class_name A pointer to a StringName with the name of a class that was previously added as an editor plugin. + */ +typedef void (*GDExtensionInterfaceEditorRemovePlugin)(GDExtensionConstStringNamePtr p_class_name); + #ifdef __cplusplus } #endif diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index 5d3037b4ec..596a2dfac1 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -485,6 +485,24 @@ EditorPlugin *EditorData::get_editor_plugin(int p_idx) { return editor_plugins[p_idx]; } +void EditorData::add_extension_editor_plugin(const StringName &p_class_name, EditorPlugin *p_plugin) { + ERR_FAIL_COND(extension_editor_plugins.has(p_class_name)); + extension_editor_plugins.insert(p_class_name, p_plugin); +} + +void EditorData::remove_extension_editor_plugin(const StringName &p_class_name) { + extension_editor_plugins.erase(p_class_name); +} + +bool EditorData::has_extension_editor_plugin(const StringName &p_class_name) { + return extension_editor_plugins.has(p_class_name); +} + +EditorPlugin *EditorData::get_extension_editor_plugin(const StringName &p_class_name) { + EditorPlugin **plugin = extension_editor_plugins.getptr(p_class_name); + return plugin == nullptr ? nullptr : *plugin; +} + void EditorData::add_custom_type(const String &p_type, const String &p_inherits, const Ref<Script> &p_script, const Ref<Texture2D> &p_icon) { ERR_FAIL_COND_MSG(p_script.is_null(), "It's not a reference to a valid Script object."); CustomType ct; diff --git a/editor/editor_data.h b/editor/editor_data.h index 7ca04b5680..28fe13e537 100644 --- a/editor/editor_data.h +++ b/editor/editor_data.h @@ -124,6 +124,7 @@ public: private: Vector<EditorPlugin *> editor_plugins; + HashMap<StringName, EditorPlugin *> extension_editor_plugins; struct PropertyData { String name; @@ -170,6 +171,11 @@ public: int get_editor_plugin_count() const; EditorPlugin *get_editor_plugin(int p_idx); + void add_extension_editor_plugin(const StringName &p_class_name, EditorPlugin *p_plugin); + void remove_extension_editor_plugin(const StringName &p_class_name); + bool has_extension_editor_plugin(const StringName &p_class_name); + EditorPlugin *get_extension_editor_plugin(const StringName &p_class_name); + void add_undo_redo_inspector_hook_callback(Callable p_callable); // Callbacks should have this signature: void (Object* undo_redo, Object *modified_object, String property, Variant new_value) void remove_undo_redo_inspector_hook_callback(Callable p_callable); const Vector<Callable> get_undo_redo_inspector_hook_callback(); diff --git a/editor/editor_interface.h b/editor/editor_interface.h index 1436bf83af..95fa0dd64f 100644 --- a/editor/editor_interface.h +++ b/editor/editor_interface.h @@ -41,6 +41,7 @@ class EditorCommandPalette; class EditorFileSystem; class EditorInspector; class EditorPaths; +class EditorPlugin; class EditorResourcePreview; class EditorSelection; class EditorSettings; @@ -83,6 +84,9 @@ public: void set_plugin_enabled(const String &p_plugin, bool p_enabled); bool is_plugin_enabled(const String &p_plugin) const; + void add_editor_plugin(EditorPlugin *p_plugin); + void remove_editor_plugin(EditorPlugin *p_plugin); + // Editor GUI. Control *get_base_control() const; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index ce7702d5b0..10c260310f 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -3239,6 +3239,30 @@ void EditorNode::remove_editor_plugin(EditorPlugin *p_editor, bool p_config_chan } } +void EditorNode::add_extension_editor_plugin(const StringName &p_class_name) { + ERR_FAIL_COND_MSG(!ClassDB::class_exists(p_class_name), vformat("No such editor plugin registered: %s", p_class_name)); + ERR_FAIL_COND_MSG(!ClassDB::is_parent_class(p_class_name, SNAME("EditorPlugin")), vformat("Class is not an editor plugin: %s", p_class_name)); + ERR_FAIL_COND_MSG(singleton->editor_data.has_extension_editor_plugin(p_class_name), vformat("Editor plugin already added for class: %s", p_class_name)); + + EditorPlugin *plugin = Object::cast_to<EditorPlugin>(ClassDB::instantiate(p_class_name)); + singleton->editor_data.add_extension_editor_plugin(p_class_name, plugin); + add_editor_plugin(plugin); +} + +void EditorNode::remove_extension_editor_plugin(const StringName &p_class_name) { + // If we're exiting, the editor plugins will get cleaned up anyway, so don't do anything. + if (singleton->exiting) { + return; + } + + ERR_FAIL_COND_MSG(!singleton->editor_data.has_extension_editor_plugin(p_class_name), vformat("No editor plugin added for class: %s", p_class_name)); + + EditorPlugin *plugin = singleton->editor_data.get_extension_editor_plugin(p_class_name); + remove_editor_plugin(plugin); + memfree(plugin); + singleton->editor_data.remove_extension_editor_plugin(p_class_name); +} + void EditorNode::_update_addon_config() { if (_initializing_plugins) { return; @@ -7768,6 +7792,12 @@ EditorNode::EditorNode() { add_editor_plugin(EditorPlugins::create(i)); } + for (const StringName &extension_class_name : GDExtensionEditorPlugins::get_extension_classes()) { + add_extension_editor_plugin(extension_class_name); + } + GDExtensionEditorPlugins::editor_node_add_plugin = &EditorNode::add_extension_editor_plugin; + GDExtensionEditorPlugins::editor_node_remove_plugin = &EditorNode::remove_extension_editor_plugin; + for (int i = 0; i < plugin_init_callback_count; i++) { plugin_init_callbacks[i](); } diff --git a/editor/editor_node.h b/editor/editor_node.h index 66da019560..c92601a44a 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -739,6 +739,9 @@ public: static void add_editor_plugin(EditorPlugin *p_editor, bool p_config_changed = false); static void remove_editor_plugin(EditorPlugin *p_editor, bool p_config_changed = false); + static void add_extension_editor_plugin(const StringName &p_class_name); + static void remove_extension_editor_plugin(const StringName &p_class_name); + static void add_plugin_init_callback(EditorPluginInitializeCallback p_callback); static void add_init_callback(EditorNodeInitCallback p_callback) { _init_callbacks.push_back(p_callback); } static void add_build_callback(EditorBuildCallback p_callback); |