Merge pull request #77010 from dsnopek/gdextension-editor-plugins
Allow GDExtensions to add editor plugins
This commit is contained in:
commit
699b66b62d
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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]();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue