Browse Source

Merge pull request #12948 from vnen/vs-custom-nodes

Create API to add and remove VisualScript custom nodes
Rémi Verschelde 7 years ago
parent
commit
4d08e7c420

+ 6 - 0
modules/visual_script/config.py

@@ -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"

+ 46 - 0
modules/visual_script/doc_classes/VisualScriptEditor.xml

@@ -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>

+ 11 - 0
modules/visual_script/register_types.cpp

@@ -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);

+ 5 - 0
modules/visual_script/visual_script.cpp

@@ -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>());

+ 1 - 0
modules/visual_script/visual_script.h

@@ -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);
 

+ 43 - 0
modules/visual_script/visual_script_editor.cpp

@@ -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

+ 23 - 0
modules/visual_script/visual_script_editor.h

@@ -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