Create API to add and remove VisualScript custom nodes

This makes a VisualScriptEditor singleton, which gives plugins the
ability to register their own custom nodes. Those will be available for
insertion in the Visual Script editor, under the "Custom Nodes"
category.
This commit is contained in:
George Marques 2017-11-15 13:57:24 -02:00
parent 9543801d51
commit 0284727e7b
No known key found for this signature in database
GPG key ID: 046BD46A3201E43D
7 changed files with 135 additions and 0 deletions

View file

@ -6,3 +6,9 @@ def can_build(platform):
def configure(env):
pass
def get_doc_classes():
return ["VisualScriptEditor"]
def get_doc_path():
return "doc_classes"

View file

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualScriptEditor" inherits="Object" category="Core" version="3.0.alpha.custom_build">
<brief_description>
</brief_description>
<description>
</description>
<tutorials>
</tutorials>
<demos>
</demos>
<methods>
<method name="add_custom_node">
<return type="void">
</return>
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="category" type="String">
</argument>
<argument index="2" name="script" type="Script">
</argument>
<description>
Add a custom Visual Script node to the editor. It'll be placed under "Custom Nodes" with the [code]category[/code] as the parameter.
</description>
</method>
<method name="remove_custom_node">
<return type="void">
</return>
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="category" type="String">
</argument>
<description>
Remove a custom Visual Script node from the editor. Custom nodes already placed on scripts won't be removed.
</description>
</method>
</methods>
<signals>
<signal name="custom_nodes_updated">
<description>
Emitted when a custom Visual Script node is added or removed.
</description>
</signal>
</signals>
<constants>
</constants>
</class>

View file

@ -29,6 +29,7 @@
/*************************************************************************/
#include "register_types.h"
#include "core/engine.h"
#include "io/resource_loader.h"
#include "visual_script.h"
#include "visual_script_builtin_funcs.h"
@ -40,6 +41,9 @@
#include "visual_script_yield_nodes.h"
VisualScriptLanguage *visual_script_language = NULL;
#ifdef TOOLS_ENABLED
static _VisualScriptEditor *vs_editor_singleton = NULL;
#endif
void register_visual_script_types() {
@ -107,6 +111,10 @@ void register_visual_script_types() {
register_visual_script_expression_node();
#ifdef TOOLS_ENABLED
ClassDB::register_class<_VisualScriptEditor>();
vs_editor_singleton = memnew(_VisualScriptEditor);
Engine::get_singleton()->add_singleton(Engine::Singleton("VisualScriptEditor", _VisualScriptEditor::get_singleton()));
VisualScriptEditor::register_editor();
#endif
}
@ -119,6 +127,9 @@ void unregister_visual_script_types() {
#ifdef TOOLS_ENABLED
VisualScriptEditor::free_clipboard();
if (vs_editor_singleton) {
memdelete(vs_editor_singleton);
}
#endif
if (visual_script_language)
memdelete(visual_script_language);

View file

@ -2644,6 +2644,11 @@ void VisualScriptLanguage::add_register_func(const String &p_name, VisualScriptN
register_funcs[p_name] = p_func;
}
void VisualScriptLanguage::remove_register_func(const String &p_name) {
ERR_FAIL_COND(!register_funcs.has(p_name));
register_funcs.erase(p_name);
}
Ref<VisualScriptNode> VisualScriptLanguage::create_node_from_name(const String &p_name) {
ERR_FAIL_COND_V(!register_funcs.has(p_name), Ref<VisualScriptNode>());

View file

@ -600,6 +600,7 @@ public:
virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max);
void add_register_func(const String &p_name, VisualScriptNodeRegisterFunc p_func);
void remove_register_func(const String &p_name);
Ref<VisualScriptNode> create_node_from_name(const String &p_name);
void get_registered_node_names(List<String> *r_names);

View file

@ -29,6 +29,7 @@
/*************************************************************************/
#include "visual_script_editor.h"
#include "core/script_language.h"
#include "editor/editor_node.h"
#include "editor/editor_resource_preview.h"
#include "os/input.h"
@ -3258,6 +3259,8 @@ void VisualScriptEditor::_bind_methods() {
ClassDB::bind_method("_member_rmb_selected", &VisualScriptEditor::_member_rmb_selected);
ClassDB::bind_method("_member_option", &VisualScriptEditor::_member_option);
ClassDB::bind_method("_update_available_nodes", &VisualScriptEditor::_update_available_nodes);
}
VisualScriptEditor::VisualScriptEditor() {
@ -3442,6 +3445,8 @@ VisualScriptEditor::VisualScriptEditor() {
members->connect("item_rmb_selected", this, "_member_rmb_selected");
members->set_allow_rmb_select(true);
member_popup->connect("id_pressed", this, "_member_option");
_VisualScriptEditor::get_singleton()->connect("custom_nodes_updated", this, "_update_available_nodes");
}
VisualScriptEditor::~VisualScriptEditor() {
@ -3485,4 +3490,42 @@ void VisualScriptEditor::register_editor() {
EditorNode::add_plugin_init_callback(register_editor_callback);
}
Ref<VisualScriptNode> _VisualScriptEditor::create_node_custom(const String &p_name) {
Ref<VisualScriptCustomNode> node;
node.instance();
node->set_script(singleton->custom_nodes[p_name]);
return node;
}
_VisualScriptEditor *_VisualScriptEditor::singleton = NULL;
Map<String, RefPtr> _VisualScriptEditor::custom_nodes;
_VisualScriptEditor::_VisualScriptEditor() {
singleton = this;
}
_VisualScriptEditor::~_VisualScriptEditor() {
custom_nodes.clear();
}
void _VisualScriptEditor::add_custom_node(const String &p_name, const String &p_category, const Ref<Script> &p_script) {
String node_name = "custom/" + p_category + "/" + p_name;
custom_nodes.insert(node_name, p_script.get_ref_ptr());
VisualScriptLanguage::singleton->add_register_func(node_name, &_VisualScriptEditor::create_node_custom);
emit_signal("custom_nodes_updated");
}
void _VisualScriptEditor::remove_custom_node(const String &p_name, const String &p_category) {
String node_name = "custom/" + p_category + "/" + p_name;
custom_nodes.erase(node_name);
VisualScriptLanguage::singleton->remove_register_func(node_name);
emit_signal("custom_nodes_updated");
}
void _VisualScriptEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_custom_node", "name", "category", "script"), &_VisualScriptEditor::add_custom_node);
ClassDB::bind_method(D_METHOD("remove_custom_node", "name", "category"), &_VisualScriptEditor::remove_custom_node);
ADD_SIGNAL(MethodInfo("custom_nodes_updated"));
}
#endif

View file

@ -278,6 +278,29 @@ public:
VisualScriptEditor();
~VisualScriptEditor();
};
// Singleton
class _VisualScriptEditor : public Object {
GDCLASS(_VisualScriptEditor, Object);
friend class VisualScriptLanguage;
protected:
static void _bind_methods();
static _VisualScriptEditor *singleton;
static Map<String, RefPtr> custom_nodes;
static Ref<VisualScriptNode> create_node_custom(const String &p_name);
public:
static _VisualScriptEditor *get_singleton() { return singleton; }
void add_custom_node(const String &p_name, const String &p_category, const Ref<Script> &p_script);
void remove_custom_node(const String &p_name, const String &p_category);
_VisualScriptEditor();
~_VisualScriptEditor();
};
#endif
#endif // VISUALSCRIPT_EDITOR_H