浏览代码

WIP visual scripting, not working yet but you can check out stuff

Juan Linietsky 9 年之前
父节点
当前提交
ad313097eb
共有 79 个文件被更改,包括 10306 次插入919 次删除
  1. 14 0
      core/dictionary.cpp
  2. 2 0
      core/dictionary.h
  3. 29 0
      core/io/networked_multiplayer_peer.cpp
  4. 40 0
      core/io/networked_multiplayer_peer.h
  5. 5 0
      core/make_binders.py
  6. 7 0
      core/method_bind.cpp
  7. 6 1
      core/method_bind.h
  8. 2 0
      core/object.h
  9. 1 0
      core/script_language.h
  10. 17 0
      modules/gdscript/gd_script.cpp
  11. 2 0
      modules/gdscript/gd_script.h
  12. 5 0
      modules/visual_script/SCsub
  13. 11 0
      modules/visual_script/config.py
  14. 96 0
      modules/visual_script/register_types.cpp
  15. 30 0
      modules/visual_script/register_types.h
  16. 1156 0
      modules/visual_script/visual_script.cpp
  17. 318 0
      modules/visual_script/visual_script.h
  18. 641 0
      modules/visual_script/visual_script_builtin_funcs.cpp
  19. 109 0
      modules/visual_script/visual_script_builtin_funcs.h
  20. 1956 0
      modules/visual_script/visual_script_editor.cpp
  21. 147 0
      modules/visual_script/visual_script_editor.h
  22. 418 0
      modules/visual_script/visual_script_flow_control.cpp
  23. 196 0
      modules/visual_script/visual_script_flow_control.h
  24. 1584 0
      modules/visual_script/visual_script_func_nodes.cpp
  25. 325 0
      modules/visual_script/visual_script_func_nodes.h
  26. 1297 0
      modules/visual_script/visual_script_nodes.cpp
  27. 394 0
      modules/visual_script/visual_script_nodes.h
  28. 106 7
      scene/gui/graph_edit.cpp
  29. 37 1
      scene/gui/graph_edit.h
  30. 18 6
      scene/gui/graph_node.cpp
  31. 3 1
      scene/gui/graph_node.h
  32. 3 3
      scene/resources/default_theme/default_theme.cpp
  33. 二进制
      scene/resources/default_theme/graph_node.png
  34. 二进制
      scene/resources/default_theme/graph_node_selected.png
  35. 4 4
      scene/resources/default_theme/theme_data.h
  36. 20 2
      tools/editor/code_editor.cpp
  37. 14 3
      tools/editor/code_editor.h
  38. 3 0
      tools/editor/editor_node.cpp
  39. 二进制
      tools/editor/icons/2x/icon_uninstance.png
  40. 二进制
      tools/editor/icons/2x/icon_visual_script.png
  41. 二进制
      tools/editor/icons/icon_mini_aabb.png
  42. 二进制
      tools/editor/icons/icon_mini_array.png
  43. 二进制
      tools/editor/icons/icon_mini_boolean.png
  44. 二进制
      tools/editor/icons/icon_mini_color.png
  45. 二进制
      tools/editor/icons/icon_mini_color_array.png
  46. 二进制
      tools/editor/icons/icon_mini_dictionary.png
  47. 二进制
      tools/editor/icons/icon_mini_float.png
  48. 二进制
      tools/editor/icons/icon_mini_float_array.png
  49. 二进制
      tools/editor/icons/icon_mini_image.png
  50. 二进制
      tools/editor/icons/icon_mini_input.png
  51. 二进制
      tools/editor/icons/icon_mini_int_array.png
  52. 二进制
      tools/editor/icons/icon_mini_integer.png
  53. 二进制
      tools/editor/icons/icon_mini_matrix3.png
  54. 二进制
      tools/editor/icons/icon_mini_matrix32.png
  55. 二进制
      tools/editor/icons/icon_mini_object.png
  56. 二进制
      tools/editor/icons/icon_mini_path.png
  57. 二进制
      tools/editor/icons/icon_mini_plane.png
  58. 二进制
      tools/editor/icons/icon_mini_quat.png
  59. 二进制
      tools/editor/icons/icon_mini_raw_array.png
  60. 二进制
      tools/editor/icons/icon_mini_rect2.png
  61. 二进制
      tools/editor/icons/icon_mini_rid.png
  62. 二进制
      tools/editor/icons/icon_mini_string.png
  63. 二进制
      tools/editor/icons/icon_mini_string_array.png
  64. 二进制
      tools/editor/icons/icon_mini_transform.png
  65. 二进制
      tools/editor/icons/icon_mini_variant.png
  66. 二进制
      tools/editor/icons/icon_mini_vector2.png
  67. 二进制
      tools/editor/icons/icon_mini_vector2_array.png
  68. 二进制
      tools/editor/icons/icon_mini_vector3.png
  69. 二进制
      tools/editor/icons/icon_mini_vector3_array.png
  70. 二进制
      tools/editor/icons/icon_override.png
  71. 二进制
      tools/editor/icons/icon_uninstance.png
  72. 二进制
      tools/editor/icons/icon_variant.png
  73. 二进制
      tools/editor/icons/icon_visual_script.png
  74. 二进制
      tools/editor/icons/icon_visual_shader_port.png
  75. 52 823
      tools/editor/plugins/script_editor_plugin.cpp
  76. 45 64
      tools/editor/plugins/script_editor_plugin.h
  77. 1057 0
      tools/editor/plugins/script_text_editor.cpp
  78. 112 0
      tools/editor/plugins/script_text_editor.h
  79. 24 4
      tools/editor/property_editor.cpp

+ 14 - 0
core/dictionary.cpp

@@ -232,6 +232,20 @@ Error Dictionary::parse_json(const String& p_json) {
 	return OK;
 	return OK;
 }
 }
 
 
+Dictionary Dictionary::copy() const {
+
+	Dictionary n(is_shared());
+
+	List<Variant> keys;
+	get_key_list(&keys);
+
+	for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
+		n[E->get()]=operator[](E->get());
+	}
+
+	return n;
+}
+
 String Dictionary::to_json() const {
 String Dictionary::to_json() const {
 
 
 	return JSON::print(*this);
 	return JSON::print(*this);

+ 2 - 0
core/dictionary.h

@@ -83,6 +83,8 @@ public:
 	Array keys() const;
 	Array keys() const;
 	Array values() const;
 	Array values() const;
 
 
+	Dictionary copy() const;
+
 	Dictionary(const Dictionary& p_from);
 	Dictionary(const Dictionary& p_from);
 	Dictionary(bool p_shared=false);
 	Dictionary(bool p_shared=false);
 	~Dictionary();
 	~Dictionary();

+ 29 - 0
core/io/networked_multiplayer_peer.cpp

@@ -0,0 +1,29 @@
+#include "networked_multiplayer_peer.h"
+
+
+void NetworkedMultiplayerPeer::_bind_methods() {
+
+	ObjectTypeDB::bind_method(_MD("set_transfer_mode","mode"), &NetworkedMultiplayerPeer::set_transfer_mode );
+	ObjectTypeDB::bind_method(_MD("set_target_peer","id"), &NetworkedMultiplayerPeer::set_target_peer );
+	ObjectTypeDB::bind_method(_MD("set_channel","id"), &NetworkedMultiplayerPeer::set_channel );
+
+	ObjectTypeDB::bind_method(_MD("get_packet_peer"), &NetworkedMultiplayerPeer::get_packet_peer );
+	ObjectTypeDB::bind_method(_MD("get_packet_channel"), &NetworkedMultiplayerPeer::get_packet_channel );
+
+	ObjectTypeDB::bind_method(_MD("poll"), &NetworkedMultiplayerPeer::poll );
+
+
+	BIND_CONSTANT( TARGET_ALL_PEERS );
+
+	BIND_CONSTANT( TRANSFER_MODE_UNRELIABLE );
+	BIND_CONSTANT( TRANSFER_MODE_RELIABLE );
+	BIND_CONSTANT( TRANSFER_MODE_ORDERED );
+
+	ADD_SIGNAL( MethodInfo("peer_connected",PropertyInfo(Variant::INT,"id")));
+	ADD_SIGNAL( MethodInfo("peer_disconnected",PropertyInfo(Variant::INT,"id")));
+}
+
+NetworkedMultiplayerPeer::NetworkedMultiplayerPeer() {
+
+
+}

+ 40 - 0
core/io/networked_multiplayer_peer.h

@@ -0,0 +1,40 @@
+#ifndef NETWORKED_MULTIPLAYER_PEER_H
+#define NETWORKED_MULTIPLAYER_PEER_H
+
+#include "io/packet_peer.h"
+
+class NetworkedMultiplayerPeer : public PacketPeer {
+
+	OBJ_TYPE(NetworkedMultiplayerPeer,PacketPeer);
+
+protected:
+	static void _bind_methods();
+public:
+
+	enum {
+		TARGET_ALL_PEERS=0xFFFFFF // send to this for all peers
+	};
+
+	enum TransferMode {
+		TRANSFER_MODE_UNRELIABLE,
+		TRANSFER_MODE_RELIABLE,
+		TRANSFER_MODE_ORDERED
+	};
+
+	virtual void set_transfer_mode(TransferMode p_mode)=0;
+	virtual void set_target_peer(int p_peer)=0;
+	virtual void set_channel(int p_channel)=0;
+
+
+	virtual int get_packet_peer() const=0;
+	virtual int get_packet_channel() const=0;
+
+
+	virtual void poll()=0;
+
+	NetworkedMultiplayerPeer();
+};
+
+VARIANT_ENUM_CAST( NetworkedMultiplayerPeer::TransferMode )
+
+#endif // NetworkedMultiplayerPeer_H

+ 5 - 0
core/make_binders.py

@@ -62,6 +62,8 @@ public:
 #else
 #else
 		set_argument_count($argc$);
 		set_argument_count($argc$);
 #endif
 #endif
+
+		$ifret _set_returns(true); $
 	};
 	};
 };
 };
 
 
@@ -140,6 +142,9 @@ public:
 #else
 #else
 		set_argument_count($argc$);
 		set_argument_count($argc$);
 #endif
 #endif
+		$ifret _set_returns(true); $
+
+
 	};
 	};
 };
 };
 
 

+ 7 - 0
core/method_bind.cpp

@@ -64,6 +64,12 @@ void MethodBind::_set_const(bool p_const) {
 	_const=p_const;
 	_const=p_const;
 }
 }
 
 
+void MethodBind::_set_returns(bool p_returns) {
+
+	_returns=p_returns;
+}
+
+
 StringName MethodBind::get_name() const {
 StringName MethodBind::get_name() const {
 	return name;
 	return name;
 }
 }
@@ -118,6 +124,7 @@ MethodBind::MethodBind() {
 	argument_types=NULL;
 	argument_types=NULL;
 #endif
 #endif
 	_const=false;
 	_const=false;
+	_returns=false;
 }
 }
 
 
 MethodBind::~MethodBind() {
 MethodBind::~MethodBind() {

+ 6 - 1
core/method_bind.h

@@ -154,6 +154,8 @@ VARIANT_ENUM_CAST( wchar_t );
 VARIANT_ENUM_CAST( Margin );
 VARIANT_ENUM_CAST( Margin );
 VARIANT_ENUM_CAST( Orientation );
 VARIANT_ENUM_CAST( Orientation );
 VARIANT_ENUM_CAST( HAlign );
 VARIANT_ENUM_CAST( HAlign );
+VARIANT_ENUM_CAST( Variant::Type );
+VARIANT_ENUM_CAST( Variant::Operator );
 
 
 class MethodBind {
 class MethodBind {
 
 
@@ -170,11 +172,13 @@ class MethodBind {
 	StringName ret_type;
 	StringName ret_type;
 #endif
 #endif
 	bool _const;
 	bool _const;
+	bool _returns;
 
 
 
 
 protected:
 protected:
 
 
 	void _set_const(bool p_const);
 	void _set_const(bool p_const);
+	void _set_returns(bool p_returns);
 #ifdef DEBUG_METHODS_ENABLED
 #ifdef DEBUG_METHODS_ENABLED
 	virtual Variant::Type _gen_argument_type(int p_arg) const=0;
 	virtual Variant::Type _gen_argument_type(int p_arg) const=0;
 	void _generate_argument_types(int p_count);
 	void _generate_argument_types(int p_count);
@@ -261,6 +265,7 @@ public:
 	void set_name(const StringName& p_name);
 	void set_name(const StringName& p_name);
 	_FORCE_INLINE_ int get_method_id() const { return method_id; }
 	_FORCE_INLINE_ int get_method_id() const { return method_id; }
 	_FORCE_INLINE_ bool is_const() const { return _const; }
 	_FORCE_INLINE_ bool is_const() const { return _const; }
+	_FORCE_INLINE_ bool has_return() const { return _returns; }
 
 
 
 
 	void set_default_arguments(const Vector<Variant>& p_defargs);
 	void set_default_arguments(const Vector<Variant>& p_defargs);
@@ -321,7 +326,7 @@ public:
 	virtual bool is_const() const { return false; }
 	virtual bool is_const() const { return false; }
 	virtual String get_instance_type() const { return T::get_type_static(); }
 	virtual String get_instance_type() const { return T::get_type_static(); }
 
 
-	MethodBindNative() { call_method=NULL; }
+	MethodBindNative() { call_method=NULL; _set_returns(true);}
 };
 };
 
 
 
 

+ 2 - 0
core/object.h

@@ -68,6 +68,8 @@ enum PropertyHint {
 	PROPERTY_HINT_IMAGE_COMPRESS_LOSSY,
 	PROPERTY_HINT_IMAGE_COMPRESS_LOSSY,
 	PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS,
 	PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS,
 	PROPERTY_HINT_OBJECT_ID,
 	PROPERTY_HINT_OBJECT_ID,
+	PROPERTY_HINT_TYPE_STRING, ///< a type string, the hint is the base type to choose
+	PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE, ///< so something else can provide this (used in scripts)
 	PROPERTY_HINT_MAX,
 	PROPERTY_HINT_MAX,
 };
 };
 
 

+ 1 - 0
core/script_language.h

@@ -110,6 +110,7 @@ public:
 	virtual bool get_property_default_value(const StringName& p_property,Variant& r_value) const=0;
 	virtual bool get_property_default_value(const StringName& p_property,Variant& r_value) const=0;
 
 
 	virtual void update_exports() {} //editor tool
 	virtual void update_exports() {} //editor tool
+	virtual void get_method_list(List<MethodInfo> *p_list) const=0;
 
 
 
 
 	Script() {}
 	Script() {}

+ 17 - 0
modules/gdscript/gd_script.cpp

@@ -249,6 +249,23 @@ void GDScript::_update_placeholder(PlaceHolderScriptInstance *p_placeholder) {
 }*/
 }*/
 #endif
 #endif
 
 
+
+void GDScript::get_method_list(List<MethodInfo> *p_list) const {
+
+	for (const Map<StringName,GDFunction*>::Element *E=member_functions.front();E;E=E->next()) {
+		MethodInfo mi;
+		mi.name=E->key();
+		for(int i=0;i<E->get()->get_argument_count();i++) {
+			PropertyInfo arg;
+			arg.type=Variant::NIL; //variant
+			arg.name=E->get()->get_argument_name(i);
+			mi.arguments.push_back(arg);
+		}
+
+		mi.return_val.name="var";
+		p_list->push_back(mi);
+	}
+}
 bool GDScript::get_property_default_value(const StringName& p_property, Variant &r_value) const {
 bool GDScript::get_property_default_value(const StringName& p_property, Variant &r_value) const {
 
 
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED

+ 2 - 0
modules/gdscript/gd_script.h

@@ -181,6 +181,8 @@ public:
 
 
 	bool get_property_default_value(const StringName& p_property,Variant& r_value) const;
 	bool get_property_default_value(const StringName& p_property,Variant& r_value) const;
 
 
+	virtual void get_method_list(List<MethodInfo> *p_list) const;
+
 	virtual ScriptLanguage *get_language() const;
 	virtual ScriptLanguage *get_language() const;
 
 
 	GDScript();
 	GDScript();

+ 5 - 0
modules/visual_script/SCsub

@@ -0,0 +1,5 @@
+Import('env')
+
+env.add_source_files(env.modules_sources,"*.cpp")
+
+Export('env')

+ 11 - 0
modules/visual_script/config.py

@@ -0,0 +1,11 @@
+
+
+def can_build(platform):
+  return True
+
+
+def configure(env):
+	pass
+
+
+

+ 96 - 0
modules/visual_script/register_types.cpp

@@ -0,0 +1,96 @@
+/*************************************************************************/
+/*  register_types.cpp                                                   */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                    http://www.godotengine.org                         */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur.                 */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+#include "register_types.h"
+
+#include "visual_script.h"
+#include "visual_script_editor.h"
+#include "io/resource_loader.h"
+#include "visual_script_nodes.h"
+#include "visual_script_func_nodes.h"
+#include "visual_script_builtin_funcs.h"
+#include "visual_script_flow_control.h"
+
+
+VisualScriptLanguage *visual_script_language=NULL;
+
+
+void register_visual_script_types() {
+
+	ObjectTypeDB::register_type<VisualScript>();
+	ObjectTypeDB::register_virtual_type<VisualScriptNode>();
+	ObjectTypeDB::register_type<VisualScriptFunction>();
+	ObjectTypeDB::register_type<VisualScriptOperator>();
+	ObjectTypeDB::register_type<VisualScriptVariable>();
+	ObjectTypeDB::register_type<VisualScriptConstant>();
+	ObjectTypeDB::register_type<VisualScriptIndexGet>();
+	ObjectTypeDB::register_type<VisualScriptIndexSet>();
+	ObjectTypeDB::register_type<VisualScriptGlobalConstant>();
+	ObjectTypeDB::register_type<VisualScriptMathConstant>();
+	ObjectTypeDB::register_type<VisualScriptSingleton>();
+	ObjectTypeDB::register_type<VisualScriptSceneNode>();
+
+	ObjectTypeDB::register_type<VisualScriptFunctionCall>();
+	ObjectTypeDB::register_type<VisualScriptPropertySet>();
+	ObjectTypeDB::register_type<VisualScriptPropertyGet>();
+	ObjectTypeDB::register_type<VisualScriptScriptCall>();
+	ObjectTypeDB::register_type<VisualScriptEmitSignal>();
+
+	ObjectTypeDB::register_type<VisualScriptReturn>();
+	ObjectTypeDB::register_type<VisualScriptCondition>();
+	ObjectTypeDB::register_type<VisualScriptWhile>();
+	ObjectTypeDB::register_type<VisualScriptIterator>();
+	ObjectTypeDB::register_type<VisualScriptSequence>();
+
+	ObjectTypeDB::register_type<VisualScriptBuiltinFunc>();
+
+	visual_script_language=memnew( VisualScriptLanguage );
+	//script_language_gd->init();
+	ScriptServer::register_language(visual_script_language);
+
+	register_visual_script_nodes();
+	register_visual_script_func_nodes();
+	register_visual_script_builtin_func_node();
+	register_visual_script_flow_control_nodes();
+
+#ifdef TOOLS_ENABLED
+	VisualScriptEditor::register_editor();
+#endif
+
+
+}
+
+void unregister_visual_script_types() {
+
+
+	ScriptServer::unregister_language(visual_script_language);
+
+	if (visual_script_language)
+		memdelete( visual_script_language );
+
+}

+ 30 - 0
modules/visual_script/register_types.h

@@ -0,0 +1,30 @@
+/*************************************************************************/
+/*  register_types.h                                                     */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                    http://www.godotengine.org                         */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur.                 */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+void register_visual_script_types();
+void unregister_visual_script_types();

+ 1156 - 0
modules/visual_script/visual_script.cpp

@@ -0,0 +1,1156 @@
+#include "visual_script.h"
+#include "visual_script_nodes.h"
+
+void VisualScriptNode::_bind_methods() {
+
+	ObjectTypeDB::bind_method(_MD("get_visual_script:VisualScript"),&VisualScriptNode::get_visual_script);
+	ADD_SIGNAL(MethodInfo("ports_changed"));
+}
+
+
+Ref<VisualScript> VisualScriptNode::get_visual_script() const {
+
+	if (scripts_used.size())
+		return Ref<VisualScript>(scripts_used.front()->get());
+
+	return Ref<VisualScript>();
+
+}
+
+////////////////
+
+/////////////////////
+
+VisualScriptNodeInstance::~VisualScriptNodeInstance() {
+
+}
+
+void VisualScript::add_function(const StringName& p_name) {
+
+	ERR_FAIL_COND(!String(p_name).is_valid_identifier());
+	ERR_FAIL_COND(functions.has(p_name));
+
+	functions[p_name]=Function();
+}
+
+bool VisualScript::has_function(const StringName& p_name) const {
+
+	return functions.has(p_name);
+
+}
+void VisualScript::remove_function(const StringName& p_name) {
+
+	ERR_FAIL_COND(!functions.has(p_name));
+
+	for (Map<int,Function::NodeData>::Element *E=functions[p_name].nodes.front();E;E=E->next()) {
+
+		E->get().node->disconnect("ports_changed",this,"_node_ports_changed");
+		E->get().node->scripts_used.erase(this);
+	}
+
+	functions.erase(p_name);
+
+}
+
+void VisualScript::rename_function(const StringName& p_name,const StringName& p_new_name) {
+
+	ERR_FAIL_COND(!functions.has(p_name));
+	if (p_new_name==p_name)
+		return;
+
+	ERR_FAIL_COND(!String(p_new_name).is_valid_identifier());
+
+	ERR_FAIL_COND(functions.has(p_new_name));
+	ERR_FAIL_COND(variables.has(p_new_name));
+	ERR_FAIL_COND(custom_signals.has(p_new_name));
+
+	functions[p_new_name]=functions[p_name];
+	functions.erase(p_name);
+
+}
+
+void VisualScript::get_function_list(List<StringName> *r_functions) const {
+
+	for (const Map<StringName,Function>::Element *E=functions.front();E;E=E->next()) {
+		r_functions->push_back(E->key());
+	}
+
+	r_functions->sort_custom<StringName::AlphCompare>();
+
+}
+
+int VisualScript::get_function_node_id(const StringName& p_name) const {
+
+	ERR_FAIL_COND_V(!functions.has(p_name),-1);
+
+	return functions[p_name].function_id;
+
+}
+
+
+void VisualScript::_node_ports_changed(int p_id) {
+
+
+	StringName function;
+
+	for (Map<StringName,Function>::Element *E=functions.front();E;E=E->next()) {
+
+		if (E->get().nodes.has(p_id)) {
+			function=E->key();
+			break;
+		}
+	}
+
+	ERR_FAIL_COND(function==StringName());
+
+	Function &func = functions[function];
+	Ref<VisualScriptNode> vsn = func.nodes[p_id].node;
+
+	//must revalidate all the functions
+
+	{
+		List<SequenceConnection> to_remove;
+
+		for (Set<SequenceConnection>::Element *E=func.sequence_connections.front();E;E=E->next()) {
+			if (E->get().from_node==p_id && E->get().from_output>=vsn->get_output_sequence_port_count()) {
+
+				to_remove.push_back(E->get());
+			}
+			if (E->get().to_node==p_id && !vsn->has_input_sequence_port()) {
+
+				to_remove.push_back(E->get());
+			}
+		}
+
+		while(to_remove.size()) {
+			func.sequence_connections.erase(to_remove.front()->get());
+			to_remove.pop_front();
+		}
+	}
+
+	{
+
+		List<DataConnection> to_remove;
+
+
+		for (Set<DataConnection>::Element *E=func.data_connections.front();E;E=E->next()) {
+			if (E->get().from_node==p_id && E->get().from_port>=vsn->get_output_value_port_count()) {
+				to_remove.push_back(E->get());
+			}
+			if (E->get().to_node==p_id && E->get().to_port>=vsn->get_input_value_port_count()) {
+				to_remove.push_back(E->get());
+			}
+		}
+
+		while(to_remove.size()) {
+			func.data_connections.erase(to_remove.front()->get());
+			to_remove.pop_front();
+		}
+	}
+
+	emit_signal("node_ports_changed",function,p_id);
+}
+
+void VisualScript::add_node(const StringName& p_func,int p_id, const Ref<VisualScriptNode>& p_node, const Point2 &p_pos) {
+
+	ERR_FAIL_COND(!functions.has(p_func));
+
+
+	for (Map<StringName,Function>::Element *E=functions.front();E;E=E->next()) {
+
+		ERR_FAIL_COND(E->get().nodes.has(p_id)); //id can exist only one in script, even for different functions
+	}
+
+	Function &func = functions[p_func];
+
+
+	if (p_node->cast_to<VisualScriptFunction>()) {
+		//the function indeed
+		ERR_EXPLAIN("A function node already has been set here.");
+		ERR_FAIL_COND(func.function_id>=0);
+
+		func.function_id=p_id;
+	}
+
+	Function::NodeData nd;
+	nd.node=p_node;
+	nd.pos=p_pos;
+
+	Ref<VisualScriptNode> vsn = p_node;
+	vsn->connect("ports_changed",this,"_node_ports_changed",varray(p_id));
+	vsn->scripts_used.insert(this);
+
+
+
+	func.nodes[p_id]=nd;
+}
+
+void VisualScript::remove_node(const StringName& p_func,int p_id){
+
+	ERR_FAIL_COND(!functions.has(p_func));
+	Function &func = functions[p_func];
+
+	ERR_FAIL_COND(!func.nodes.has(p_id));
+	{
+		List<SequenceConnection> to_remove;
+
+		for (Set<SequenceConnection>::Element *E=func.sequence_connections.front();E;E=E->next()) {
+			if (E->get().from_node==p_id || E->get().to_node==p_id) {
+				to_remove.push_back(E->get());
+			}
+		}
+
+		while(to_remove.size()) {
+			func.sequence_connections.erase(to_remove.front()->get());
+			to_remove.pop_front();
+		}
+	}
+
+	{
+
+		List<DataConnection> to_remove;
+
+
+		for (Set<DataConnection>::Element *E=func.data_connections.front();E;E=E->next()) {
+			if (E->get().from_node==p_id || E->get().to_node==p_id) {
+				to_remove.push_back(E->get());
+			}
+		}
+
+		while(to_remove.size()) {
+			func.data_connections.erase(to_remove.front()->get());
+			to_remove.pop_front();
+		}
+	}
+
+	if (func.nodes[p_id].node->cast_to<VisualScriptFunction>()) {
+		func.function_id=-1; //revert to invalid
+	}
+
+	func.nodes[p_id].node->disconnect("ports_changed",this,"_node_ports_changed");
+	func.nodes[p_id].node->scripts_used.erase(this);
+
+	func.nodes.erase(p_id);
+
+
+}
+
+
+
+Ref<VisualScriptNode> VisualScript::get_node(const StringName& p_func,int p_id) const{
+
+	ERR_FAIL_COND_V(!functions.has(p_func),Ref<VisualScriptNode>());
+	const Function &func = functions[p_func];
+
+	ERR_FAIL_COND_V(!func.nodes.has(p_id),Ref<VisualScriptNode>());
+
+	return func.nodes[p_id].node;
+}
+
+void VisualScript::set_node_pos(const StringName& p_func,int p_id,const Point2& p_pos) {
+
+	ERR_FAIL_COND(!functions.has(p_func));
+	Function &func = functions[p_func];
+
+	ERR_FAIL_COND(!func.nodes.has(p_id));
+	func.nodes[p_id].pos=p_pos;
+}
+
+Point2 VisualScript::get_node_pos(const StringName& p_func,int p_id) const{
+
+	ERR_FAIL_COND_V(!functions.has(p_func),Point2());
+	const Function &func = functions[p_func];
+
+	ERR_FAIL_COND_V(!func.nodes.has(p_id),Point2());
+	return func.nodes[p_id].pos;
+}
+
+
+void VisualScript::get_node_list(const StringName& p_func,List<int> *r_nodes) const{
+
+	ERR_FAIL_COND(!functions.has(p_func));
+	const Function &func = functions[p_func];
+
+	for (const Map<int,Function::NodeData>::Element *E=func.nodes.front();E;E=E->next()) {
+		r_nodes->push_back(E->key());
+	}
+
+}
+
+
+void VisualScript::sequence_connect(const StringName& p_func,int p_from_node,int p_from_output,int p_to_node){
+
+	ERR_FAIL_COND(!functions.has(p_func));
+	Function &func = functions[p_func];
+
+
+	SequenceConnection sc;
+	sc.from_node=p_from_node;
+	sc.from_output=p_from_output;
+	sc.to_node=p_to_node;
+	ERR_FAIL_COND(func.sequence_connections.has(sc));
+
+	func.sequence_connections.insert(sc);
+
+}
+
+void VisualScript::sequence_disconnect(const StringName& p_func,int p_from_node,int p_from_output,int p_to_node){
+
+	ERR_FAIL_COND(!functions.has(p_func));
+	Function &func = functions[p_func];
+
+	SequenceConnection sc;
+	sc.from_node=p_from_node;
+	sc.from_output=p_from_output;
+	sc.to_node=p_to_node;
+	ERR_FAIL_COND(!func.sequence_connections.has(sc));
+
+	func.sequence_connections.erase(sc);
+
+}
+
+bool VisualScript::has_sequence_connection(const StringName& p_func,int p_from_node,int p_from_output,int p_to_node) const{
+
+	ERR_FAIL_COND_V(!functions.has(p_func),false);
+	const Function &func = functions[p_func];
+
+	SequenceConnection sc;
+	sc.from_node=p_from_node;
+	sc.from_output=p_from_output;
+	sc.to_node=p_to_node;
+
+	return func.sequence_connections.has(sc);
+}
+
+void VisualScript::get_sequence_connection_list(const StringName& p_func,List<SequenceConnection> *r_connection) const {
+
+	ERR_FAIL_COND(!functions.has(p_func));
+	const Function &func = functions[p_func];
+
+	for (const Set<SequenceConnection>::Element *E=func.sequence_connections.front();E;E=E->next()) {
+		r_connection->push_back(E->get());
+	}
+}
+
+
+void VisualScript::data_connect(const StringName& p_func,int p_from_node,int p_from_port,int p_to_node,int p_to_port) {
+
+	ERR_FAIL_COND(!functions.has(p_func));
+	Function &func = functions[p_func];
+
+	DataConnection dc;
+	dc.from_node=p_from_node;
+	dc.from_port=p_from_port;
+	dc.to_node=p_to_node;
+	dc.to_port=p_to_port;
+
+	ERR_FAIL_COND( func.data_connections.has(dc));
+
+	func.data_connections.insert(dc);
+}
+
+void VisualScript::data_disconnect(const StringName& p_func,int p_from_node,int p_from_port,int p_to_node,int p_to_port) {
+
+	ERR_FAIL_COND(!functions.has(p_func));
+	Function &func = functions[p_func];
+
+	DataConnection dc;
+	dc.from_node=p_from_node;
+	dc.from_port=p_from_port;
+	dc.to_node=p_to_node;
+	dc.to_port=p_to_port;
+
+	ERR_FAIL_COND( !func.data_connections.has(dc));
+
+	func.data_connections.erase(dc);
+
+}
+
+bool VisualScript::has_data_connection(const StringName& p_func,int p_from_node,int p_from_port,int p_to_node,int p_to_port) const {
+
+	ERR_FAIL_COND_V(!functions.has(p_func),false);
+	const Function &func = functions[p_func];
+
+	DataConnection dc;
+	dc.from_node=p_from_node;
+	dc.from_port=p_from_port;
+	dc.to_node=p_to_node;
+	dc.to_port=p_to_port;
+
+	return func.data_connections.has(dc);
+
+}
+
+void VisualScript::get_data_connection_list(const StringName& p_func,List<DataConnection> *r_connection) const {
+
+	ERR_FAIL_COND(!functions.has(p_func));
+	const Function &func = functions[p_func];
+
+	for (const Set<DataConnection>::Element *E=func.data_connections.front();E;E=E->next()) {
+		r_connection->push_back(E->get());
+	}
+}
+
+void VisualScript::add_variable(const StringName& p_name,const Variant& p_default_value) {
+
+	ERR_FAIL_COND(!String(p_name).is_valid_identifier());
+	ERR_FAIL_COND(variables.has(p_name));
+
+	Variable v;
+	v.default_value=p_default_value;
+	v.info.type=p_default_value.get_type();
+	v.info.name=p_name;
+	v.info.hint=PROPERTY_HINT_NONE;
+
+	variables[p_name]=v;
+
+}
+
+bool VisualScript::has_variable(const StringName& p_name) const {
+
+	return variables.has(p_name);
+}
+
+void VisualScript::remove_variable(const StringName& p_name) {
+
+	ERR_FAIL_COND(!variables.has(p_name));
+	variables.erase(p_name);
+}
+
+void VisualScript::set_variable_default_value(const StringName& p_name,const Variant& p_value){
+
+	ERR_FAIL_COND(!variables.has(p_name));
+
+	variables[p_name].default_value=p_value;
+
+}
+Variant VisualScript::get_variable_default_value(const StringName& p_name) const{
+
+	ERR_FAIL_COND_V(!variables.has(p_name),Variant());
+	return variables[p_name].default_value;
+
+}
+void VisualScript::set_variable_info(const StringName& p_name,const PropertyInfo& p_info){
+
+	ERR_FAIL_COND(!variables.has(p_name));
+	variables[p_name].info=p_info;
+	variables[p_name].info.name=p_name;
+
+
+}
+PropertyInfo VisualScript::get_variable_info(const StringName& p_name) const{
+
+	ERR_FAIL_COND_V(!variables.has(p_name),PropertyInfo());
+	return variables[p_name].info;
+}
+
+void VisualScript::_set_variable_info(const StringName& p_name,const Dictionary& p_info) {
+
+	PropertyInfo pinfo;
+	if (p_info.has("type"))
+		pinfo.type=Variant::Type(int(p_info["type"]));
+	if (p_info.has("name"))
+		pinfo.name=p_info["name"];
+	if (p_info.has("hint"))
+		pinfo.hint=PropertyHint(int(p_info["hint"]));
+	if (p_info.has("hint_string"))
+		pinfo.hint_string=p_info["hint_string"];
+	if (p_info.has("usage"))
+		pinfo.usage=p_info["usage"];
+
+	set_variable_info(p_name,pinfo);
+}
+
+Dictionary VisualScript::_get_variable_info(const StringName& p_name) const{
+
+	PropertyInfo pinfo=get_variable_info(p_name);
+	Dictionary d;
+	d["type"]=pinfo.type;
+	d["name"]=pinfo.name;
+	d["hint"]=pinfo.hint;
+	d["hint_string"]=pinfo.hint_string;
+	d["usage"]=pinfo.usage;
+
+	return d;
+}
+
+void VisualScript::get_variable_list(List<StringName> *r_variables){
+
+
+	for (Map<StringName,Variable>::Element *E=variables.front();E;E=E->next()) {
+		r_variables->push_back(E->key());
+	}
+
+	r_variables->sort_custom<StringName::AlphCompare>();
+}
+
+
+void VisualScript::set_instance_base_type(const StringName& p_type) {
+
+	base_type=p_type;
+}
+
+
+void VisualScript::rename_variable(const StringName& p_name,const StringName& p_new_name) {
+
+	ERR_FAIL_COND(!variables.has(p_name));
+	if (p_new_name==p_name)
+		return;
+
+	ERR_FAIL_COND(!String(p_new_name).is_valid_identifier());
+
+	ERR_FAIL_COND(functions.has(p_new_name));
+	ERR_FAIL_COND(variables.has(p_new_name));
+	ERR_FAIL_COND(custom_signals.has(p_new_name));
+
+	variables[p_new_name]=variables[p_name];
+	variables.erase(p_name);
+
+}
+
+void VisualScript::add_custom_signal(const StringName& p_name) {
+
+	ERR_FAIL_COND(!String(p_name).is_valid_identifier());
+	ERR_FAIL_COND(custom_signals.has(p_name));
+
+	custom_signals[p_name]=Vector<Argument>();
+}
+
+bool VisualScript::has_custom_signal(const StringName& p_name) const {
+
+	return custom_signals.has(p_name);
+
+}
+void VisualScript::custom_signal_add_argument(const StringName& p_func,Variant::Type p_type,const String& p_name,int p_index) {
+
+	ERR_FAIL_COND(!custom_signals.has(p_func));
+	Argument arg;
+	arg.type=p_type;
+	arg.name=p_name;
+	if (p_index<0)
+		custom_signals[p_func].push_back(arg);
+	else
+		custom_signals[p_func].insert(0,arg);
+
+}
+void VisualScript::custom_signal_set_argument_type(const StringName& p_func,int p_argidx,Variant::Type p_type) {
+
+	ERR_FAIL_COND(!custom_signals.has(p_func));
+	ERR_FAIL_INDEX(p_argidx,custom_signals[p_func].size());
+	custom_signals[p_func][p_argidx].type=p_type;
+}
+Variant::Type VisualScript::custom_signal_get_argument_type(const StringName& p_func,int p_argidx) const  {
+
+	ERR_FAIL_COND_V(!custom_signals.has(p_func),Variant::NIL);
+	ERR_FAIL_INDEX_V(p_argidx,custom_signals[p_func].size(),Variant::NIL);
+	return custom_signals[p_func][p_argidx].type;
+}
+void VisualScript::custom_signal_set_argument_name(const StringName& p_func,int p_argidx,const String& p_name) {
+	ERR_FAIL_COND(!custom_signals.has(p_func));
+	ERR_FAIL_INDEX(p_argidx,custom_signals[p_func].size());
+	custom_signals[p_func][p_argidx].name=p_name;
+
+}
+String VisualScript::custom_signal_get_argument_name(const StringName& p_func,int p_argidx) const {
+
+	ERR_FAIL_COND_V(!custom_signals.has(p_func),String());
+	ERR_FAIL_INDEX_V(p_argidx,custom_signals[p_func].size(),String());
+	return custom_signals[p_func][p_argidx].name;
+
+}
+void VisualScript::custom_signal_remove_argument(const StringName& p_func,int p_argidx) {
+
+	ERR_FAIL_COND(!custom_signals.has(p_func));
+	ERR_FAIL_INDEX(p_argidx,custom_signals[p_func].size());
+	custom_signals[p_func].remove(p_argidx);
+
+}
+
+int VisualScript::custom_signal_get_argument_count(const StringName& p_func) const {
+
+	ERR_FAIL_COND_V(!custom_signals.has(p_func),0);
+	return custom_signals[p_func].size();
+
+}
+void VisualScript::custom_signal_swap_argument(const StringName& p_func,int p_argidx,int p_with_argidx) {
+
+	ERR_FAIL_COND(!custom_signals.has(p_func));
+	ERR_FAIL_INDEX(p_argidx,custom_signals[p_func].size());
+	ERR_FAIL_INDEX(p_with_argidx,custom_signals[p_func].size());
+
+	SWAP( custom_signals[p_func][p_argidx], custom_signals[p_func][p_with_argidx] );
+
+}
+void VisualScript::remove_custom_signal(const StringName& p_name) {
+
+	ERR_FAIL_COND(!custom_signals.has(p_name));
+	custom_signals.erase(p_name);
+
+}
+
+void VisualScript::rename_custom_signal(const StringName& p_name,const StringName& p_new_name) {
+
+	ERR_FAIL_COND(!custom_signals.has(p_name));
+	if (p_new_name==p_name)
+		return;
+
+	ERR_FAIL_COND(!String(p_new_name).is_valid_identifier());
+
+	ERR_FAIL_COND(functions.has(p_new_name));
+	ERR_FAIL_COND(variables.has(p_new_name));
+	ERR_FAIL_COND(custom_signals.has(p_new_name));
+
+	custom_signals[p_new_name]=custom_signals[p_name];
+	custom_signals.erase(p_name);
+
+}
+
+void VisualScript::get_custom_signal_list(List<StringName> *r_custom_signals) const {
+
+	for (const Map<StringName,Vector<Argument> >::Element *E=custom_signals.front();E;E=E->next()) {
+		r_custom_signals->push_back(E->key());
+	}
+
+	r_custom_signals->sort_custom<StringName::AlphCompare>();
+
+}
+
+int VisualScript::get_available_id() const {
+
+	int max_id=0;
+	for (Map<StringName,Function>::Element *E=functions.front();E;E=E->next()) {
+		if (E->get().nodes.empty())
+			continue;
+
+		int last_id = E->get().nodes.back()->key();
+		max_id=MAX(max_id,last_id+1);
+	}
+
+	return max_id;
+}
+
+/////////////////////////////////
+
+
+bool VisualScript::can_instance() const {
+
+	return ScriptServer::is_scripting_enabled();
+
+}
+
+
+StringName VisualScript::get_instance_base_type() const {
+
+	return base_type;
+}
+
+ScriptInstance* VisualScript::instance_create(Object *p_this) {
+
+	return NULL;
+}
+
+bool VisualScript::instance_has(const Object *p_this) const {
+
+	return false;
+}
+
+bool VisualScript::has_source_code() const {
+
+	return false;
+}
+
+String VisualScript::get_source_code() const {
+
+	return String();
+}
+
+void VisualScript::set_source_code(const String& p_code) {
+
+}
+
+Error VisualScript::reload(bool p_keep_state) {
+
+	return OK;
+}
+
+
+bool VisualScript::is_tool() const {
+
+	return false;
+}
+
+
+String VisualScript::get_node_type() const {
+
+	return String();
+}
+
+
+ScriptLanguage *VisualScript::get_language() const {
+
+	return VisualScriptLanguage::singleton;
+}
+
+
+bool VisualScript::has_script_signal(const StringName& p_signal) const {
+
+	return false;
+}
+
+void VisualScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
+
+}
+
+
+bool VisualScript::get_property_default_value(const StringName& p_property,Variant& r_value) const {
+
+	return false;
+}
+void VisualScript::get_method_list(List<MethodInfo> *p_list) const {
+
+	for (Map<StringName,Function>::Element *E=functions.front();E;E=E->next()) {
+
+		MethodInfo mi;
+		mi.name=E->key();
+		if (E->get().function_id>=0) {
+
+			Ref<VisualScriptFunction> func=E->get().nodes[E->get().function_id].node;
+			if (func.is_valid()) {
+
+				for(int i=0;i<func->get_argument_count();i++) {
+					PropertyInfo arg;
+					arg.name=func->get_argument_name(i);
+					arg.type=func->get_argument_type(i);
+					mi.arguments.push_back(arg);
+				}
+			}
+		}
+
+		p_list->push_back(mi);
+	}
+}
+
+void VisualScript::_set_data(const Dictionary& p_data) {
+
+	Dictionary d = p_data;
+	if (d.has("base_type"))
+		base_type=d["base_type"];
+
+	variables.clear();
+	Array vars=d["variables"];
+	for (int i=0;i<vars.size();i++) {
+
+		Dictionary v=vars[i];
+		add_variable(v["name"],v["default_value"]);
+		_set_variable_info(v["name"],v);
+	}
+
+
+	custom_signals.clear();
+	Array sigs=d["signals"];
+	for (int i=0;i<sigs.size();i++) {
+
+		Dictionary cs=sigs[i];
+		add_custom_signal(cs["name"]);
+
+		Array args=cs["arguments"];
+		for(int j=0;j<args.size();j+=2) {
+			custom_signal_add_argument(cs["name"],Variant::Type(int(args[j+1])),args[j]);
+		}
+	}
+
+	Array funcs=d["functions"];
+	functions.clear();
+
+	for (int i=0;i<funcs.size();i++) {
+
+		Dictionary func=funcs[i];
+
+		StringName name=func["name"];
+		//int id=func["function_id"];
+		add_function(name);
+
+		Array nodes = func["nodes"];
+
+		for(int i=0;i<nodes.size();i+=3) {
+
+			add_node(name,nodes[i],nodes[i+2],nodes[i+1]);
+		}
+
+
+		Array sequence_connections=func["sequence_connections"];
+
+		for (int j=0;j<sequence_connections.size();j+=3) {
+
+			sequence_connect(name,sequence_connections[j+0],sequence_connections[j+1],sequence_connections[j+2]);
+		}
+
+
+		Array data_connections=func["data_connections"];
+
+		for (int j=0;j<data_connections.size();j+=4) {
+
+			data_connect(name,data_connections[j+0],data_connections[j+1],data_connections[j+2],data_connections[j+3]);
+
+		}
+
+
+	}
+
+}
+
+Dictionary VisualScript::_get_data() const{
+
+	Dictionary d;
+	d["base_type"]=base_type;
+	Array vars;
+	for (const Map<StringName,Variable>::Element *E=variables.front();E;E=E->next()) {
+
+		Dictionary var = _get_variable_info(E->key());
+		var["name"]=E->key(); //make sure it's the right one
+		var["default_value"]=E->get().default_value;
+		vars.push_back(var);
+	}
+	d["variables"]=vars;
+
+	Array sigs;
+	for (const Map<StringName,Vector<Argument> >::Element *E=custom_signals.front();E;E=E->next()) {
+
+		Dictionary cs;
+		cs["name"]=E->key();
+		Array args;
+		for(int i=0;i<E->get().size();i++) {
+			args.push_back(E->get()[i].name);
+			args.push_back(E->get()[i].type);
+		}
+		cs["arguments"]=args;
+
+		sigs.push_back(cs);
+	}
+
+	d["signals"]=sigs;
+
+	Array funcs;
+
+	for (const Map<StringName,Function>::Element *E=functions.front();E;E=E->next()) {
+
+		Dictionary func;
+		func["name"]=E->key();
+		func["function_id"]=E->get().function_id;
+
+		Array nodes;
+
+		for (const Map<int,Function::NodeData>::Element *F=E->get().nodes.front();F;F=F->next()) {
+
+			nodes.push_back(F->key());
+			nodes.push_back(F->get().pos);
+			nodes.push_back(F->get().node);
+
+		}
+
+		func["nodes"]=nodes;
+
+		Array sequence_connections;
+
+		for (const Set<SequenceConnection>::Element *F=E->get().sequence_connections.front();F;F=F->next()) {
+
+			sequence_connections.push_back(F->get().from_node);
+			sequence_connections.push_back(F->get().from_output);
+			sequence_connections.push_back(F->get().to_node);
+
+		}
+
+
+		func["sequence_connections"]=sequence_connections;
+
+		Array data_connections;
+
+		for (const Set<DataConnection>::Element *F=E->get().data_connections.front();F;F=F->next()) {
+
+			data_connections.push_back(F->get().from_node);
+			data_connections.push_back(F->get().from_port);
+			data_connections.push_back(F->get().to_node);
+			data_connections.push_back(F->get().to_port);
+
+		}
+
+
+		func["data_connections"]=data_connections;
+
+		funcs.push_back(func);
+
+	}
+
+	d["functions"]=funcs;
+
+
+	return d;
+
+}
+
+void VisualScript::_bind_methods() {
+
+
+
+	ObjectTypeDB::bind_method(_MD("_node_ports_changed"),&VisualScript::_node_ports_changed);
+
+	ObjectTypeDB::bind_method(_MD("add_function","name"),&VisualScript::add_function);
+	ObjectTypeDB::bind_method(_MD("has_function","name"),&VisualScript::has_function);	
+	ObjectTypeDB::bind_method(_MD("remove_function","name"),&VisualScript::remove_function);
+	ObjectTypeDB::bind_method(_MD("rename_function","name","new_name"),&VisualScript::rename_function);
+
+	ObjectTypeDB::bind_method(_MD("add_node","func","id","node","pos"),&VisualScript::add_node,DEFVAL(Point2()));
+	ObjectTypeDB::bind_method(_MD("remove_node","func","id"),&VisualScript::remove_node);
+	ObjectTypeDB::bind_method(_MD("get_function_node_id","name"),&VisualScript::get_function_node_id);
+
+	ObjectTypeDB::bind_method(_MD("get_node","func","id"),&VisualScript::get_node);
+	ObjectTypeDB::bind_method(_MD("set_node_pos","func","id","pos"),&VisualScript::set_node_pos);
+	ObjectTypeDB::bind_method(_MD("get_node_pos","func","id"),&VisualScript::get_node_pos);
+
+	ObjectTypeDB::bind_method(_MD("sequence_connect","func","from_node","from_output","to_node"),&VisualScript::sequence_connect);
+	ObjectTypeDB::bind_method(_MD("sequence_disconnect","func","from_node","from_output","to_node"),&VisualScript::sequence_disconnect);
+	ObjectTypeDB::bind_method(_MD("has_sequence_connection","func","from_node","from_output","to_node"),&VisualScript::has_sequence_connection);
+
+	ObjectTypeDB::bind_method(_MD("data_connect","func","from_node","from_port","to_node","to_port"),&VisualScript::data_connect);
+	ObjectTypeDB::bind_method(_MD("data_disconnect","func","from_node","from_port","to_node","to_port"),&VisualScript::data_disconnect);
+	ObjectTypeDB::bind_method(_MD("has_data_connection","func","from_node","from_port","to_node","to_port"),&VisualScript::has_data_connection);
+
+	ObjectTypeDB::bind_method(_MD("add_variable","name","default_value"),&VisualScript::add_variable,DEFVAL(Variant()));
+	ObjectTypeDB::bind_method(_MD("has_variable","name"),&VisualScript::has_variable);
+	ObjectTypeDB::bind_method(_MD("remove_variable","name"),&VisualScript::remove_variable);
+	ObjectTypeDB::bind_method(_MD("set_variable_default_value","name","value"),&VisualScript::set_variable_default_value);
+	ObjectTypeDB::bind_method(_MD("get_variable_default_value","name"),&VisualScript::get_variable_default_value);
+	ObjectTypeDB::bind_method(_MD("set_variable_info","name","value"),&VisualScript::_set_variable_info);
+	ObjectTypeDB::bind_method(_MD("get_variable_info","name"),&VisualScript::_get_variable_info);
+	ObjectTypeDB::bind_method(_MD("rename_variable","name","new_name"),&VisualScript::rename_variable);
+
+	ObjectTypeDB::bind_method(_MD("add_custom_signal","name"),&VisualScript::add_custom_signal);
+	ObjectTypeDB::bind_method(_MD("has_custom_signal","name"),&VisualScript::has_custom_signal);
+	ObjectTypeDB::bind_method(_MD("custom_signal_add_argument","name","type","argname","index"),&VisualScript::custom_signal_add_argument,DEFVAL(-1));
+	ObjectTypeDB::bind_method(_MD("custom_signal_set_argument_type","name","argidx","type"),&VisualScript::custom_signal_set_argument_type);
+	ObjectTypeDB::bind_method(_MD("custom_signal_get_argument_type","name","argidx"),&VisualScript::custom_signal_get_argument_type);
+	ObjectTypeDB::bind_method(_MD("custom_signal_set_argument_name","name","argidx","argname"),&VisualScript::custom_signal_set_argument_name);
+	ObjectTypeDB::bind_method(_MD("custom_signal_get_argument_name","name","argidx"),&VisualScript::custom_signal_get_argument_name);
+	ObjectTypeDB::bind_method(_MD("custom_signal_remove_argument","argidx"),&VisualScript::custom_signal_remove_argument);
+	ObjectTypeDB::bind_method(_MD("custom_signal_get_argument_count","name"),&VisualScript::custom_signal_get_argument_count);
+	ObjectTypeDB::bind_method(_MD("custom_signal_swap_argument","name","argidx","withidx"),&VisualScript::custom_signal_swap_argument);
+	ObjectTypeDB::bind_method(_MD("remove_custom_signal","name"),&VisualScript::remove_custom_signal);
+	ObjectTypeDB::bind_method(_MD("rename_custom_signal","name","new_name"),&VisualScript::rename_custom_signal);
+
+	//ObjectTypeDB::bind_method(_MD("set_variable_info","name","info"),&VScript::set_variable_info);
+	//ObjectTypeDB::bind_method(_MD("get_variable_info","name"),&VScript::set_variable_info);
+
+	ObjectTypeDB::bind_method(_MD("set_instance_base_type","type"),&VisualScript::set_instance_base_type);
+
+	ObjectTypeDB::bind_method(_MD("_set_data","data"),&VisualScript::_set_data);
+	ObjectTypeDB::bind_method(_MD("_get_data"),&VisualScript::_get_data);
+
+	ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY,"data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_data"),_SCS("_get_data"));
+
+	ADD_SIGNAL(MethodInfo("node_ports_changed",PropertyInfo(Variant::STRING,"function"),PropertyInfo(Variant::INT,"id")));
+}
+
+VisualScript::VisualScript() {
+
+	base_type="Object";
+
+}
+
+VisualScript::~VisualScript() {
+
+	while(!functions.empty()) {
+		remove_function(functions.front()->key());
+	}
+
+}
+
+////////////////////////////////////////////
+
+
+String VisualScriptLanguage::get_name() const {
+
+	return "VisualScript";
+}
+
+/* LANGUAGE FUNCTIONS */
+void VisualScriptLanguage::init() {
+
+
+}
+String VisualScriptLanguage::get_type() const {
+
+	return "VisualScript";
+}
+String VisualScriptLanguage::get_extension() const {
+
+	return "vs";
+}
+Error VisualScriptLanguage::execute_file(const String& p_path) {
+
+	return OK;
+}
+void VisualScriptLanguage::finish() {
+
+
+}
+
+/* EDITOR FUNCTIONS */
+void VisualScriptLanguage::get_reserved_words(List<String> *p_words) const {
+
+
+}
+void VisualScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const {
+
+
+}
+void VisualScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const {
+
+
+}
+String VisualScriptLanguage::get_template(const String& p_class_name, const String& p_base_class_name) const {
+
+	return String();
+}
+bool VisualScriptLanguage::validate(const String& p_script, int &r_line_error,int &r_col_error,String& r_test_error, const String& p_path,List<String> *r_functions) const {
+
+	return false;
+}
+Script *VisualScriptLanguage::create_script() const {
+
+	return memnew( VisualScript );
+}
+bool VisualScriptLanguage::has_named_classes() const {
+
+	return false;
+}
+int VisualScriptLanguage::find_function(const String& p_function,const String& p_code) const {
+
+	return -1;
+}
+String VisualScriptLanguage::make_function(const String& p_class,const String& p_name,const StringArray& p_args) const {
+
+	return String();
+}
+
+void VisualScriptLanguage::auto_indent_code(String& p_code,int p_from_line,int p_to_line) const {
+
+
+}
+void VisualScriptLanguage::add_global_constant(const StringName& p_variable,const Variant& p_value) {
+
+
+}
+
+
+/* DEBUGGER FUNCTIONS */
+
+String VisualScriptLanguage::debug_get_error() const {
+
+	return String();
+}
+int VisualScriptLanguage::debug_get_stack_level_count() const {
+
+	return 0;
+}
+int VisualScriptLanguage::debug_get_stack_level_line(int p_level) const {
+
+	return 0;
+}
+String VisualScriptLanguage::debug_get_stack_level_function(int p_level) const {
+
+	return String();
+}
+String VisualScriptLanguage::debug_get_stack_level_source(int p_level) const {
+
+	return String();
+}
+void VisualScriptLanguage::debug_get_stack_level_locals(int p_level,List<String> *p_locals, List<Variant> *p_values, int p_max_subitems,int p_max_depth) {
+
+
+}
+void VisualScriptLanguage::debug_get_stack_level_members(int p_level,List<String> *p_members, List<Variant> *p_values, int p_max_subitems,int p_max_depth) {
+
+
+}
+void VisualScriptLanguage::debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems,int p_max_depth) {
+
+
+}
+String VisualScriptLanguage::debug_parse_stack_level_expression(int p_level,const String& p_expression,int p_max_subitems,int p_max_depth) {
+
+	return String();
+}
+
+
+void VisualScriptLanguage::reload_all_scripts() {
+
+
+}
+void VisualScriptLanguage::reload_tool_script(const Ref<Script>& p_script,bool p_soft_reload) {
+
+
+}
+/* LOADER FUNCTIONS */
+
+void VisualScriptLanguage::get_recognized_extensions(List<String> *p_extensions) const {
+
+	p_extensions->push_back("vs");
+
+}
+void VisualScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const {
+
+
+}
+void VisualScriptLanguage::get_public_constants(List<Pair<String,Variant> > *p_constants) const {
+
+
+}
+
+void VisualScriptLanguage::profiling_start() {
+
+
+}
+void VisualScriptLanguage::profiling_stop() {
+
+
+}
+
+int VisualScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr,int p_info_max) {
+
+	return 0;
+}
+
+int VisualScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr,int p_info_max) {
+
+	return 0;
+}
+
+
+VisualScriptLanguage* VisualScriptLanguage::singleton=NULL;
+
+
+void VisualScriptLanguage::add_register_func(const String& p_name,VisualScriptNodeRegisterFunc p_func) {
+
+	ERR_FAIL_COND(register_funcs.has(p_name));
+	register_funcs[p_name]=p_func;
+}
+
+Ref<VisualScriptNode> VisualScriptLanguage::create_node_from_name(const String& p_name) {
+
+	ERR_FAIL_COND_V(!register_funcs.has(p_name),Ref<VisualScriptNode>());
+
+	return register_funcs[p_name](p_name);
+}
+
+void VisualScriptLanguage::get_registered_node_names(List<String> *r_names) {
+
+	for (Map<String,VisualScriptNodeRegisterFunc>::Element *E=register_funcs.front();E;E=E->next()) {
+		r_names->push_back(E->key());
+	}
+}
+
+
+VisualScriptLanguage::VisualScriptLanguage() {
+
+	singleton=this;
+}

+ 318 - 0
modules/visual_script/visual_script.h

@@ -0,0 +1,318 @@
+#ifndef VSCRIPT_H
+#define VSCRIPT_H
+
+#include "script_language.h"
+
+
+class VScriptInstance;
+class VisualScriptNodeInstance;
+class VisualScript;
+
+class VisualScriptNode : public Resource {
+	OBJ_TYPE(VisualScriptNode,Resource)
+
+friend class VisualScript;
+
+	Set<VisualScript*> scripts_used;
+protected:
+	static void _bind_methods();
+public:
+
+	Ref<VisualScript> get_visual_script() const;
+
+	virtual int get_output_sequence_port_count() const=0;
+	virtual bool has_input_sequence_port() const=0;
+
+	virtual String get_output_sequence_port_text(int p_port) const=0;
+
+	virtual int get_input_value_port_count() const=0;
+	virtual int get_output_value_port_count() const=0;
+
+
+	virtual PropertyInfo get_input_value_port_info(int p_idx) const=0;
+	virtual PropertyInfo get_output_value_port_info(int p_idx) const=0;
+
+	virtual String get_caption() const=0;
+	virtual String get_text() const=0;
+
+	virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance)=0;
+
+};
+
+
+class VisualScriptNodeInstance {
+public:
+
+	virtual int step()=0; //do a step, return which sequence port to go out
+
+	virtual Variant get_input_value(int p_idx)=0;
+	virtual Variant get_output_value(int p_idx)=0;
+
+	virtual VisualScriptNode* get_node()=0;
+
+	virtual ~VisualScriptNodeInstance();
+};
+
+
+class VisualScript : public Script {
+
+	OBJ_TYPE( VisualScript, Script )
+
+	RES_BASE_EXTENSION("vs");
+
+public:
+
+	struct SequenceConnection {
+
+		union {
+
+			struct {
+				uint64_t from_node : 24;
+				uint64_t from_output : 16;
+				uint64_t to_node : 24;
+			};
+			uint64_t id;
+		};
+
+		bool operator<(const SequenceConnection& p_connection) const {
+
+			return id<p_connection.id;
+		}
+	};
+
+	struct DataConnection {
+
+		union {
+
+			struct {
+				uint64_t from_node : 24;
+				uint64_t from_port : 8;
+				uint64_t to_node : 24;
+				uint64_t to_port : 8;
+			};
+			uint64_t id;
+		};
+
+		bool operator<(const DataConnection& p_connection) const {
+
+			return id<p_connection.id;
+		}
+	};
+
+
+private:
+
+	StringName base_type;
+	struct Argument {
+		String name;
+		Variant::Type type;
+	};
+
+	struct Function {
+		struct NodeData {
+			Point2 pos;
+			Ref<VisualScriptNode> node;
+		};
+
+		Map<int,NodeData> nodes;
+
+		Set<SequenceConnection> sequence_connections;
+
+		Set<DataConnection> data_connections;
+
+		int function_id;
+
+		Function() { function_id=-1; }
+
+	};
+
+	struct Variable {
+		PropertyInfo info;
+		Variant default_value;
+	};
+
+
+
+	Map<StringName,Function> functions;
+	Map<StringName,Variable> variables;
+	Map<StringName,Vector<Argument> > custom_signals;
+
+	void _set_variable_info(const StringName& p_name,const Dictionary& p_info);
+	Dictionary _get_variable_info(const StringName& p_name) const;
+
+
+	void _set_data(const Dictionary& p_data);
+	Dictionary _get_data() const;
+
+protected:
+
+	void _node_ports_changed(int p_id);
+	static void _bind_methods();
+public:
+
+
+	void add_function(const StringName& p_name);
+	bool has_function(const StringName& p_name) const;
+	void remove_function(const StringName& p_name);
+	void rename_function(const StringName& p_name,const StringName& p_new_name);
+	void get_function_list(List<StringName> *r_functions) const;
+	int get_function_node_id(const StringName& p_name) const;
+
+
+	void add_node(const StringName& p_func,int p_id,const Ref<VisualScriptNode>& p_node,const Point2& p_pos=Point2());
+	void remove_node(const StringName& p_func,int p_id);
+	Ref<VisualScriptNode> get_node(const StringName& p_func,int p_id) const;
+	void set_node_pos(const StringName& p_func,int p_id,const Point2& p_pos);
+	Point2 get_node_pos(const StringName& p_func,int p_id) const;
+	void get_node_list(const StringName& p_func,List<int> *r_nodes) const;
+
+	void sequence_connect(const StringName& p_func,int p_from_node,int p_from_output,int p_to_node);
+	void sequence_disconnect(const StringName& p_func,int p_from_node,int p_from_output,int p_to_node);
+	bool has_sequence_connection(const StringName& p_func,int p_from_node,int p_from_output,int p_to_node) const;
+	void get_sequence_connection_list(const StringName& p_func,List<SequenceConnection> *r_connection) const;
+
+	void data_connect(const StringName& p_func,int p_from_node,int p_from_port,int p_to_node,int p_to_port);
+	void data_disconnect(const StringName& p_func,int p_from_node,int p_from_port,int p_to_node,int p_to_port);
+	bool has_data_connection(const StringName& p_func,int p_from_node,int p_from_port,int p_to_node,int p_to_port) const;
+	void get_data_connection_list(const StringName& p_func,List<DataConnection> *r_connection) const;
+
+	void add_variable(const StringName& p_name,const Variant& p_default_value=Variant());
+	bool has_variable(const StringName& p_name) const;
+	void remove_variable(const StringName& p_name);
+	void set_variable_default_value(const StringName& p_name,const Variant& p_value);
+	Variant get_variable_default_value(const StringName& p_name) const;
+	void set_variable_info(const StringName& p_name,const PropertyInfo& p_info);
+	PropertyInfo get_variable_info(const StringName& p_name) const;
+	void get_variable_list(List<StringName> *r_variables);
+	void rename_variable(const StringName& p_name,const StringName& p_new_name);
+
+
+	void add_custom_signal(const StringName& p_name);
+	bool has_custom_signal(const StringName& p_name) const;
+	void custom_signal_add_argument(const StringName& p_func,Variant::Type p_type,const String& p_name,int p_index=-1);
+	void custom_signal_set_argument_type(const StringName& p_func,int p_argidx,Variant::Type p_type);
+	Variant::Type custom_signal_get_argument_type(const StringName& p_func,int p_argidx) const;
+	void custom_signal_set_argument_name(const StringName& p_func,int p_argidx,const String& p_name);
+	String custom_signal_get_argument_name(const StringName& p_func,int p_argidx) const;
+	void custom_signal_remove_argument(const StringName& p_func,int p_argidx);
+	int custom_signal_get_argument_count(const StringName& p_func) const;
+	void custom_signal_swap_argument(const StringName& p_func,int p_argidx,int p_with_argidx);
+	void remove_custom_signal(const StringName& p_name);
+	void rename_custom_signal(const StringName& p_name,const StringName& p_new_name);
+
+	void get_custom_signal_list(List<StringName> *r_custom_signals) const;
+
+	int get_available_id() const;
+
+	void set_instance_base_type(const StringName& p_type);
+
+	virtual bool can_instance() const;
+
+	virtual StringName get_instance_base_type() const;
+	virtual ScriptInstance* instance_create(Object *p_this);
+	virtual bool instance_has(const Object *p_this) const;
+
+
+	virtual bool has_source_code() const;
+	virtual String get_source_code() const;
+	virtual void set_source_code(const String& p_code);
+	virtual Error reload(bool p_keep_state=false);
+
+	virtual bool is_tool() const;
+
+	virtual String get_node_type() const;
+
+	virtual ScriptLanguage *get_language() const;
+
+	virtual bool has_script_signal(const StringName& p_signal) const;
+	virtual void get_script_signal_list(List<MethodInfo> *r_signals) const;
+
+	virtual bool get_property_default_value(const StringName& p_property,Variant& r_value) const;
+	virtual void get_method_list(List<MethodInfo> *p_list) const;
+
+
+	VisualScript();
+	~VisualScript();
+};
+
+
+typedef Ref<VisualScriptNode> (*VisualScriptNodeRegisterFunc)(const String& p_type);
+
+class VisualScriptLanguage : public ScriptLanguage {
+
+	Map<String,VisualScriptNodeRegisterFunc> register_funcs;
+public:
+
+	static VisualScriptLanguage* singleton;
+
+	virtual String get_name() const;
+
+	/* LANGUAGE FUNCTIONS */
+	virtual void init();
+	virtual String get_type() const;
+	virtual String get_extension() const;
+	virtual Error execute_file(const String& p_path) ;
+	virtual void finish();
+
+	/* EDITOR FUNCTIONS */
+	virtual void get_reserved_words(List<String> *p_words) const;
+	virtual void get_comment_delimiters(List<String> *p_delimiters) const;
+	virtual void get_string_delimiters(List<String> *p_delimiters) const;
+	virtual String get_template(const String& p_class_name, const String& p_base_class_name) const;
+	virtual bool validate(const String& p_script, int &r_line_error,int &r_col_error,String& r_test_error, const String& p_path="",List<String> *r_functions=NULL) const;
+	virtual Script *create_script() const;
+	virtual bool has_named_classes() const;
+	virtual int find_function(const String& p_function,const String& p_code) const;
+	virtual String make_function(const String& p_class,const String& p_name,const StringArray& p_args) const;
+	virtual void auto_indent_code(String& p_code,int p_from_line,int p_to_line) const;
+	virtual void add_global_constant(const StringName& p_variable,const Variant& p_value);
+
+
+	/* DEBUGGER FUNCTIONS */
+
+	virtual String debug_get_error() const;
+	virtual int debug_get_stack_level_count() const;
+	virtual int debug_get_stack_level_line(int p_level) const;
+	virtual String debug_get_stack_level_function(int p_level) const;
+	virtual String debug_get_stack_level_source(int p_level) const;
+	virtual void debug_get_stack_level_locals(int p_level,List<String> *p_locals, List<Variant> *p_values, int p_max_subitems=-1,int p_max_depth=-1);
+	virtual void debug_get_stack_level_members(int p_level,List<String> *p_members, List<Variant> *p_values, int p_max_subitems=-1,int p_max_depth=-1);
+	virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems=-1,int p_max_depth=-1);
+	virtual String debug_parse_stack_level_expression(int p_level,const String& p_expression,int p_max_subitems=-1,int p_max_depth=-1);
+
+
+	virtual void reload_all_scripts();
+	virtual void reload_tool_script(const Ref<Script>& p_script,bool p_soft_reload);
+	/* LOADER FUNCTIONS */
+
+	virtual void get_recognized_extensions(List<String> *p_extensions) const;
+	virtual void get_public_functions(List<MethodInfo> *p_functions) const;
+	virtual void get_public_constants(List<Pair<String,Variant> > *p_constants) const;
+
+	virtual void profiling_start();
+	virtual void profiling_stop();
+
+	virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr,int p_info_max);
+	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);
+	Ref<VisualScriptNode> create_node_from_name(const String& p_name);
+	void get_registered_node_names(List<String> *r_names);
+
+
+	VisualScriptLanguage();
+
+};
+
+//aid for registering
+template<class T>
+static Ref<VisualScriptNode> create_node_generic(const String& p_name) {
+
+	Ref<T> node;
+	node.instance();
+	return node;
+}
+
+
+
+#endif // VSCRIPT_H

+ 641 - 0
modules/visual_script/visual_script_builtin_funcs.cpp

@@ -0,0 +1,641 @@
+#include "visual_script_builtin_funcs.h"
+
+
+const char* VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX]={
+	"sin",
+	"cos",
+	"tan",
+	"sinh",
+	"cosh",
+	"tanh",
+	"asin",
+	"acos",
+	"atan",
+	"atan2",
+	"sqrt",
+	"fmod",
+	"fposmod",
+	"floor",
+	"ceil",
+	"round",
+	"abs",
+	"sign",
+	"pow",
+	"log",
+	"exp",
+	"is_nan",
+	"is_inf",
+	"ease",
+	"decimals",
+	"stepify",
+	"lerp",
+	"dectime",
+	"randomize",
+	"randi",
+	"randf",
+	"rand_range",
+	"seed",
+	"rand_seed",
+	"deg2rad",
+	"rad2deg",
+	"linear2db",
+	"db2linear",
+	"max",
+	"min",
+	"clamp",
+	"nearest_po2",
+	"weakref",
+	"funcref",
+	"convert",
+	"typeof",
+	"type_exists",
+	"str",
+	"print",
+	"printerr",
+	"printraw",
+	"var2str",
+	"str2var",
+	"var2bytes",
+	"bytes2var",
+};
+
+
+
+int VisualScriptBuiltinFunc::get_output_sequence_port_count() const {
+
+	return 1;
+}
+
+bool VisualScriptBuiltinFunc::has_input_sequence_port() const{
+
+	return true;
+}
+
+int VisualScriptBuiltinFunc::get_input_value_port_count() const{
+
+
+	switch(func) {
+
+		case MATH_RANDOMIZE:
+		case MATH_RAND:
+		case MATH_RANDF:
+			return 0;
+		case MATH_SIN:
+		case MATH_COS:
+		case MATH_TAN:
+		case MATH_SINH:
+		case MATH_COSH:
+		case MATH_TANH:
+		case MATH_ASIN:
+		case MATH_ACOS:
+		case MATH_ATAN:
+		case MATH_SQRT:
+		case MATH_FLOOR:
+		case MATH_CEIL:
+		case MATH_ROUND:
+		case MATH_ABS:
+		case MATH_SIGN:
+		case MATH_LOG:
+		case MATH_EXP:
+		case MATH_ISNAN:
+		case MATH_ISINF:
+		case MATH_DECIMALS:
+		case MATH_SEED:
+		case MATH_RANDSEED:
+		case MATH_DEG2RAD:
+		case MATH_RAD2DEG:
+		case MATH_LINEAR2DB:
+		case MATH_DB2LINEAR:
+		case LOGIC_NEAREST_PO2:
+		case OBJ_WEAKREF:
+		case TYPE_OF:
+		case TEXT_STR:
+		case TEXT_PRINT:
+		case TEXT_PRINTERR:
+		case TEXT_PRINTRAW:
+		case VAR_TO_STR:
+		case STR_TO_VAR:
+		case VAR_TO_BYTES:
+		case BYTES_TO_VAR:
+		case TYPE_EXISTS:
+			return 1;
+		case MATH_ATAN2:
+		case MATH_FMOD:
+		case MATH_FPOSMOD:
+		case MATH_POW:
+		case MATH_EASE:
+		case MATH_STEPIFY:
+		case MATH_RANDOM:
+		case LOGIC_MAX:
+		case LOGIC_MIN:
+		case FUNC_FUNCREF:
+		case TYPE_CONVERT:
+			return 2;
+		case MATH_LERP:
+		case MATH_DECTIME:
+		case LOGIC_CLAMP:
+			return 3;
+		case FUNC_MAX:{}
+
+	}
+	return 0;
+}
+int VisualScriptBuiltinFunc::get_output_value_port_count() const{
+
+	switch(func) {
+		case MATH_RANDOMIZE:
+		case TEXT_PRINT:
+		case TEXT_PRINTERR:
+		case TEXT_PRINTRAW:
+		case MATH_SEED:
+			return 0;
+		case MATH_RANDSEED:
+			return 2;
+		default:
+			return 1;
+	}
+
+	return 1;
+}
+
+String VisualScriptBuiltinFunc::get_output_sequence_port_text(int p_port) const {
+
+	return String();
+}
+
+PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const{
+
+	switch(func) {
+
+		case MATH_SIN:
+		case MATH_COS:
+		case MATH_TAN:
+		case MATH_SINH:
+		case MATH_COSH:
+		case MATH_TANH:
+		case MATH_ASIN:
+		case MATH_ACOS:
+		case MATH_ATAN:
+		case MATH_ATAN2:
+		case MATH_SQRT: {
+			return PropertyInfo(Variant::REAL,"num");
+		} break;
+		case MATH_FMOD:
+		case MATH_FPOSMOD: {
+			if (p_idx==0)
+				return PropertyInfo(Variant::REAL,"x");
+			else
+				return PropertyInfo(Variant::REAL,"y");
+		} break;
+		case MATH_FLOOR:
+		case MATH_CEIL:
+		case MATH_ROUND:
+		case MATH_ABS:
+		case MATH_SIGN: {
+			return PropertyInfo(Variant::REAL,"num");
+
+		} break;
+
+		case MATH_POW: {
+			if (p_idx==0)
+				return PropertyInfo(Variant::REAL,"x");
+			else
+				return PropertyInfo(Variant::REAL,"y");
+		} break;
+		case MATH_LOG:
+		case MATH_EXP:
+		case MATH_ISNAN:
+		case MATH_ISINF: {
+			return PropertyInfo(Variant::REAL,"num");
+		} break;
+		case MATH_EASE: {
+			if (p_idx==0)
+				return PropertyInfo(Variant::REAL,"s");
+			else
+				return PropertyInfo(Variant::REAL,"curve");
+		} break;
+		case MATH_DECIMALS: {
+			return PropertyInfo(Variant::REAL,"step");
+		} break;
+		case MATH_STEPIFY: {
+			if (p_idx==0)
+				return PropertyInfo(Variant::REAL,"s");
+			else
+				return PropertyInfo(Variant::REAL,"steps");
+		} break;
+		case MATH_LERP: {
+			if (p_idx==0)
+				return PropertyInfo(Variant::REAL,"from");
+			else if (p_idx==1)
+				return PropertyInfo(Variant::REAL,"to");
+			else
+				return PropertyInfo(Variant::REAL,"weight");
+
+		} break;
+		case MATH_DECTIME: {
+			if (p_idx==0)
+				return PropertyInfo(Variant::REAL,"value");
+			else if (p_idx==1)
+				return PropertyInfo(Variant::REAL,"amount");
+			else
+				return PropertyInfo(Variant::REAL,"step");
+		} break;
+		case MATH_RANDOMIZE: {
+
+		} break;
+		case MATH_RAND: {
+
+		} break;
+		case MATH_RANDF: {
+
+		} break;
+		case MATH_RANDOM: {
+			if (p_idx==0)
+				return PropertyInfo(Variant::REAL,"from");
+			else
+				return PropertyInfo(Variant::REAL,"to");
+		} break;
+		case MATH_SEED: {
+			return PropertyInfo(Variant::INT,"seed");
+		} break;
+		case MATH_RANDSEED: {
+			return PropertyInfo(Variant::INT,"seed");
+		} break;
+		case MATH_DEG2RAD: {
+			return PropertyInfo(Variant::REAL,"deg");
+		} break;
+		case MATH_RAD2DEG: {
+			return PropertyInfo(Variant::REAL,"rad");
+		} break;
+		case MATH_LINEAR2DB: {
+			return PropertyInfo(Variant::REAL,"nrg");
+		} break;
+		case MATH_DB2LINEAR: {
+			return PropertyInfo(Variant::REAL,"db");
+		} break;
+		case LOGIC_MAX: {
+			if (p_idx==0)
+				return PropertyInfo(Variant::REAL,"a");
+			else
+				return PropertyInfo(Variant::REAL,"b");
+		} break;
+		case LOGIC_MIN: {
+			if (p_idx==0)
+				return PropertyInfo(Variant::REAL,"a");
+			else
+				return PropertyInfo(Variant::REAL,"b");
+		} break;
+		case LOGIC_CLAMP: {
+			if (p_idx==0)
+				return PropertyInfo(Variant::REAL,"a");
+			else if (p_idx==0)
+				return PropertyInfo(Variant::REAL,"min");
+			else
+				return PropertyInfo(Variant::REAL,"max");
+		} break;
+		case LOGIC_NEAREST_PO2: {
+			return PropertyInfo(Variant::INT,"num");
+		} break;
+		case OBJ_WEAKREF: {
+
+			return PropertyInfo(Variant::OBJECT,"source");
+
+		} break;
+		case FUNC_FUNCREF: {
+
+			if (p_idx==0)
+				return PropertyInfo(Variant::OBJECT,"instance");
+			else
+				return PropertyInfo(Variant::STRING,"funcname");
+
+		} break;
+		case TYPE_CONVERT: {
+
+			if (p_idx==0)
+				return PropertyInfo(Variant::NIL,"what");
+			else
+				return PropertyInfo(Variant::STRING,"type");
+		} break;
+		case TYPE_OF: {
+			return PropertyInfo(Variant::NIL,"what");
+
+		} break;
+		case TYPE_EXISTS: {
+
+			return PropertyInfo(Variant::STRING,"type");
+
+		} break;
+		case TEXT_STR: {
+
+			return PropertyInfo(Variant::NIL,"value");
+
+
+		} break;
+		case TEXT_PRINT: {
+
+			return PropertyInfo(Variant::NIL,"value");
+
+		} break;
+		case TEXT_PRINTERR: {
+			return PropertyInfo(Variant::NIL,"value");
+
+		} break;
+		case TEXT_PRINTRAW: {
+
+			return PropertyInfo(Variant::NIL,"value");
+
+		} break;
+		case VAR_TO_STR: {
+			return PropertyInfo(Variant::NIL,"var");
+
+		} break;
+		case STR_TO_VAR: {
+
+			return PropertyInfo(Variant::STRING,"string");
+		} break;
+		case VAR_TO_BYTES: {
+			return PropertyInfo(Variant::NIL,"var");
+
+		} break;
+		case BYTES_TO_VAR: {
+
+			return PropertyInfo(Variant::RAW_ARRAY,"bytes");
+		} break;
+		case FUNC_MAX:{}
+	}
+
+	return PropertyInfo();
+}
+
+PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) const{
+
+	Variant::Type t=Variant::NIL;
+	switch(func) {
+
+		case MATH_SIN:
+		case MATH_COS:
+		case MATH_TAN:
+		case MATH_SINH:
+		case MATH_COSH:
+		case MATH_TANH:
+		case MATH_ASIN:
+		case MATH_ACOS:
+		case MATH_ATAN:
+		case MATH_ATAN2:
+		case MATH_SQRT:
+		case MATH_FMOD:
+		case MATH_FPOSMOD:
+		case MATH_FLOOR:
+		case MATH_CEIL:
+			t=Variant::REAL;
+		case MATH_ROUND: {
+			t=Variant::INT;
+		} break;
+		case MATH_ABS: {
+			t=Variant::NIL;
+		} break;
+		case MATH_SIGN: {
+			t=Variant::NIL;
+		} break;
+		case MATH_POW:
+		case MATH_LOG:
+		case MATH_EXP: {
+			t=Variant::REAL;
+		} break;
+		case MATH_ISNAN:
+		case MATH_ISINF: {
+			t=Variant::BOOL;
+		} break;
+		case MATH_EASE: {
+			t=Variant::REAL;
+		} break;
+		case MATH_DECIMALS: {
+			t=Variant::INT;
+		} break;
+		case MATH_STEPIFY:
+		case MATH_LERP:
+		case MATH_DECTIME: {
+			t=Variant::REAL;
+
+		} break;
+		case MATH_RANDOMIZE: {
+
+		} break;
+		case MATH_RAND: {
+
+			t=Variant::INT;
+		} break;
+		case MATH_RANDF:
+		case MATH_RANDOM: {
+			t=Variant::REAL;
+		} break;
+		case MATH_SEED: {
+
+		} break;
+		case MATH_RANDSEED: {
+
+			if (p_idx==0)
+				return PropertyInfo(Variant::INT,"rnd");
+			else
+				return PropertyInfo(Variant::INT,"seed");
+		} break;
+		case MATH_DEG2RAD:
+		case MATH_RAD2DEG:
+		case MATH_LINEAR2DB:
+		case MATH_DB2LINEAR: {
+			t=Variant::REAL;
+		} break;
+		case LOGIC_MAX:
+		case LOGIC_MIN:
+		case LOGIC_CLAMP: {
+
+
+		} break;
+
+		case LOGIC_NEAREST_PO2: {
+			t=Variant::NIL;
+		} break;
+		case OBJ_WEAKREF: {
+
+			t=Variant::OBJECT;
+
+		} break;
+		case FUNC_FUNCREF: {
+
+			t=Variant::OBJECT;
+
+		} break;
+		case TYPE_CONVERT: {
+
+
+
+		} break;
+		case TYPE_OF: {
+			t=Variant::INT;
+
+		} break;
+		case TYPE_EXISTS: {
+
+			t=Variant::BOOL;
+
+		} break;
+		case TEXT_STR: {
+
+			t=Variant::STRING;
+
+		} break;
+		case TEXT_PRINT: {
+
+
+		} break;
+		case TEXT_PRINTERR: {
+
+		} break;
+		case TEXT_PRINTRAW: {
+
+		} break;
+		case VAR_TO_STR: {
+			t=Variant::STRING;
+		} break;
+		case STR_TO_VAR: {
+
+		} break;
+		case VAR_TO_BYTES: {
+			t=Variant::RAW_ARRAY;
+
+		} break;
+		case BYTES_TO_VAR: {
+
+
+		} break;
+		case FUNC_MAX:{}
+	}
+
+	return PropertyInfo(t,"");
+}
+
+String VisualScriptBuiltinFunc::get_caption() const {
+
+	return "BuiltinFunc";
+}
+
+String VisualScriptBuiltinFunc::get_text() const {
+
+	return func_name[func];
+}
+
+void VisualScriptBuiltinFunc::set_func(BuiltinFunc p_which) {
+
+	ERR_FAIL_INDEX(p_which,FUNC_MAX);
+	func=p_which;
+	_change_notify();
+	emit_signal("ports_changed");
+}
+
+VisualScriptBuiltinFunc::BuiltinFunc VisualScriptBuiltinFunc::get_func() {
+	return func;
+}
+
+
+
+VisualScriptNodeInstance* VisualScriptBuiltinFunc::instance(VScriptInstance* p_instance) {
+
+	return NULL;
+}
+
+void VisualScriptBuiltinFunc::_bind_methods() {
+
+	ObjectTypeDB::bind_method(_MD("set_func","which"),&VisualScriptBuiltinFunc::set_func);
+	ObjectTypeDB::bind_method(_MD("get_func"),&VisualScriptBuiltinFunc::get_func);
+
+	String cc;
+
+	for(int i=0;i<FUNC_MAX;i++) {
+
+		if (i>0)
+			cc+=",";
+		cc+=func_name[i];
+	}
+	ADD_PROPERTY(PropertyInfo(Variant::INT,"function",PROPERTY_HINT_ENUM,cc),_SCS("set_func"),_SCS("get_func"));
+}
+
+VisualScriptBuiltinFunc::VisualScriptBuiltinFunc() {
+
+	func=MATH_SIN;
+}
+
+template<VisualScriptBuiltinFunc::BuiltinFunc func>
+static Ref<VisualScriptNode> create_builtin_func_node(const String& p_name) {
+
+	Ref<VisualScriptBuiltinFunc> node;
+	node.instance();
+	node->set_func(func);
+	return node;
+}
+
+void register_visual_script_builtin_func_node() {
+
+
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/sin",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SIN>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/cos",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_COS>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/tan",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_TAN>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/sinh",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SINH>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/cosh",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_COSH>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/tanh",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_TANH>);
+
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/asin",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ASIN>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/acos",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ACOS>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/atan",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ATAN>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/atan2",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ATAN2>);
+
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/sqrt",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SQRT>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/fmod",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_FMOD>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/fposmod",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_FPOSMOD>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/floor",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_FLOOR>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/ceil",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_CEIL>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/round",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ROUND>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/abs",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ABS>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/sign",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SIGN>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/pow",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_POW>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/log",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LOG>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/exp",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_EXP>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/isnan",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ISNAN>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/isinf",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ISINF>);
+
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/ease",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_EASE>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/decimals",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DECIMALS>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/stepify",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_STEPIFY>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/lerp",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LERP>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/dectime",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DECTIME>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/randomize",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDOMIZE>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/rand",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RAND>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/randf",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDF>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/random",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDOM>);
+
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/seed",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SEED>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/randseed",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDSEED>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/deg2rad",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DEG2RAD>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/rad2deg",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RAD2DEG>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/linear2db",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LINEAR2DB>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/db2linear",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DB2LINEAR>);
+
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/max",create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_MAX>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/min",create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_MIN>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/clamp",create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_CLAMP>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/nearest_po2",create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_NEAREST_PO2>);
+
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/weakref",create_builtin_func_node<VisualScriptBuiltinFunc::OBJ_WEAKREF>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/funcref",create_builtin_func_node<VisualScriptBuiltinFunc::FUNC_FUNCREF>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/convert",create_builtin_func_node<VisualScriptBuiltinFunc::TYPE_CONVERT>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/typeof",create_builtin_func_node<VisualScriptBuiltinFunc::TYPE_OF>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/type_exists",create_builtin_func_node<VisualScriptBuiltinFunc::TYPE_EXISTS>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/str",create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_STR>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/print",create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINT>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/printerr",create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINTERR>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/printraw",create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINTRAW>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/var2str",create_builtin_func_node<VisualScriptBuiltinFunc::VAR_TO_STR>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/str2var",create_builtin_func_node<VisualScriptBuiltinFunc::STR_TO_VAR>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/var2bytes",create_builtin_func_node<VisualScriptBuiltinFunc::VAR_TO_BYTES>);
+	VisualScriptLanguage::singleton->add_register_func("functions/builtin/bytes2var",create_builtin_func_node<VisualScriptBuiltinFunc::BYTES_TO_VAR>);
+
+}

+ 109 - 0
modules/visual_script/visual_script_builtin_funcs.h

@@ -0,0 +1,109 @@
+#ifndef VISUAL_SCRIPT_BUILTIN_FUNCS_H
+#define VISUAL_SCRIPT_BUILTIN_FUNCS_H
+
+#include "visual_script.h"
+
+
+class VisualScriptBuiltinFunc : public VisualScriptNode {
+
+	OBJ_TYPE(VisualScriptBuiltinFunc,VisualScriptNode)
+public:
+
+	enum BuiltinFunc {
+		MATH_SIN,
+		MATH_COS,
+		MATH_TAN,
+		MATH_SINH,
+		MATH_COSH,
+		MATH_TANH,
+		MATH_ASIN,
+		MATH_ACOS,
+		MATH_ATAN,
+		MATH_ATAN2,
+		MATH_SQRT,
+		MATH_FMOD,
+		MATH_FPOSMOD,
+		MATH_FLOOR,
+		MATH_CEIL,
+		MATH_ROUND,
+		MATH_ABS,
+		MATH_SIGN,
+		MATH_POW,
+		MATH_LOG,
+		MATH_EXP,
+		MATH_ISNAN,
+		MATH_ISINF,
+		MATH_EASE,
+		MATH_DECIMALS,
+		MATH_STEPIFY,
+		MATH_LERP,
+		MATH_DECTIME,
+		MATH_RANDOMIZE,
+		MATH_RAND,
+		MATH_RANDF,
+		MATH_RANDOM,
+		MATH_SEED,
+		MATH_RANDSEED,
+		MATH_DEG2RAD,
+		MATH_RAD2DEG,
+		MATH_LINEAR2DB,
+		MATH_DB2LINEAR,
+		LOGIC_MAX,
+		LOGIC_MIN,
+		LOGIC_CLAMP,
+		LOGIC_NEAREST_PO2,
+		OBJ_WEAKREF,
+		FUNC_FUNCREF,
+		TYPE_CONVERT,
+		TYPE_OF,
+		TYPE_EXISTS,
+		TEXT_STR,
+		TEXT_PRINT,
+		TEXT_PRINTERR,
+		TEXT_PRINTRAW,
+		VAR_TO_STR,
+		STR_TO_VAR,
+		VAR_TO_BYTES,
+		BYTES_TO_VAR,
+		FUNC_MAX
+	};
+
+private:
+	static const char* func_name[FUNC_MAX];
+	BuiltinFunc func;
+protected:
+	static void _bind_methods();
+public:
+
+	virtual int get_output_sequence_port_count() const;
+	virtual bool has_input_sequence_port() const;
+
+
+	virtual String get_output_sequence_port_text(int p_port) const;
+
+
+	virtual int get_input_value_port_count() const;
+	virtual int get_output_value_port_count() const;
+
+
+	virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+	virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+	virtual String get_caption() const;
+	virtual String get_text() const;
+
+	void set_func(BuiltinFunc p_which);
+	BuiltinFunc get_func();
+
+	virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance);
+
+	VisualScriptBuiltinFunc();
+};
+
+VARIANT_ENUM_CAST(VisualScriptBuiltinFunc::BuiltinFunc)
+
+
+void register_visual_script_builtin_func_node();
+
+
+#endif // VISUAL_SCRIPT_BUILTIN_FUNCS_H

+ 1956 - 0
modules/visual_script/visual_script_editor.cpp

@@ -0,0 +1,1956 @@
+#include "visual_script_editor.h"
+#include "tools/editor/editor_node.h"
+#include "visual_script_nodes.h"
+#include "visual_script_flow_control.h"
+#include "visual_script_func_nodes.h"
+
+class VisualScriptEditorSignalEdit : public Object {
+
+	OBJ_TYPE(VisualScriptEditorSignalEdit,Object)
+
+	StringName sig;
+public:
+	UndoRedo *undo_redo;
+	Ref<VisualScript> script;
+
+
+protected:
+
+	static void _bind_methods() {
+		ObjectTypeDB::bind_method("_sig_changed",&VisualScriptEditorSignalEdit::_sig_changed);
+	}
+
+	void _sig_changed() {
+
+		_change_notify();
+	}
+
+	bool _set(const StringName& p_name, const Variant& p_value) {
+
+		if (sig==StringName())
+			return false;
+
+		if (p_name=="argument_count") {
+
+			int new_argc=p_value;
+			int argc = script->custom_signal_get_argument_count(sig);
+			if (argc==new_argc)
+				return true;
+
+			undo_redo->create_action("Change Signal Arguments");
+
+
+
+			if (new_argc < argc) {
+				for(int i=new_argc;i<argc;i++) {
+					undo_redo->add_do_method(script.ptr(),"custom_signal_remove_argument",sig,new_argc);
+					undo_redo->add_undo_method(script.ptr(),"custom_signal_add_argument",sig,script->custom_signal_get_argument_name(sig,i),script->custom_signal_get_argument_type(sig,i),-1);
+				}
+			} else if (new_argc>argc) {
+
+				for(int i=argc;i<new_argc;i++) {
+
+					undo_redo->add_do_method(script.ptr(),"custom_signal_add_argument",sig,Variant::NIL,"arg"+itos(i+1),-1);
+					undo_redo->add_undo_method(script.ptr(),"custom_signal_remove_argument",sig,argc);
+				}
+			}
+
+			undo_redo->add_do_method(this,"_sig_changed");
+			undo_redo->add_undo_method(this,"_sig_changed");
+
+			undo_redo->commit_action();
+
+			return true;
+		}
+		if (String(p_name).begins_with("argument/")) {
+			int idx = String(p_name).get_slice("/",1).to_int()-1;
+			ERR_FAIL_INDEX_V(idx,script->custom_signal_get_argument_count(sig),false);
+			String what = String(p_name).get_slice("/",2);
+			if (what=="type") {
+
+				int old_type = script->custom_signal_get_argument_type(sig,idx);
+				int new_type=p_value;
+				undo_redo->create_action("Change Argument Type");
+				undo_redo->add_do_method(script.ptr(),"custom_signal_set_argument_type",sig,idx,new_type);
+				undo_redo->add_undo_method(script.ptr(),"custom_signal_set_argument_type",sig,idx,old_type);
+				undo_redo->commit_action();
+
+				return true;
+			}
+
+			if (what=="name") {
+
+				String old_name = script->custom_signal_get_argument_name(sig,idx);
+				String new_name=p_value;
+				undo_redo->create_action("Change Argument name");
+				undo_redo->add_do_method(script.ptr(),"custom_signal_set_argument_name",sig,idx,new_name);
+				undo_redo->add_undo_method(script.ptr(),"custom_signal_set_argument_name",sig,idx,old_name);
+				undo_redo->commit_action();
+				return true;
+			}
+
+
+		}
+
+
+		return false;
+	}
+
+	bool _get(const StringName& p_name,Variant &r_ret) const {
+
+		if (sig==StringName())
+			return false;
+
+		if (p_name=="argument_count") {
+			r_ret = script->custom_signal_get_argument_count(sig);
+			return true;
+		}
+		if (String(p_name).begins_with("argument/")) {
+			int idx = String(p_name).get_slice("/",1).to_int()-1;
+			ERR_FAIL_INDEX_V(idx,script->custom_signal_get_argument_count(sig),false);
+			String what = String(p_name).get_slice("/",2);
+			if (what=="type") {
+				r_ret = script->custom_signal_get_argument_type(sig,idx);
+				return true;
+			}
+			if (what=="name") {
+				r_ret = script->custom_signal_get_argument_name(sig,idx);
+				return true;
+			}
+
+
+
+		}
+
+		return false;
+	}
+	void _get_property_list( List<PropertyInfo> *p_list) const {
+
+		if (sig==StringName())
+			return;
+
+		p_list->push_back(PropertyInfo(Variant::INT,"argument_count",PROPERTY_HINT_RANGE,"0,256"));
+		String argt="Variant";
+		for(int i=1;i<Variant::VARIANT_MAX;i++) {
+			argt+=","+Variant::get_type_name(Variant::Type(i));
+		}
+
+		for(int i=0;i<script->custom_signal_get_argument_count(sig);i++) {
+			p_list->push_back(PropertyInfo(Variant::INT,"argument/"+itos(i+1)+"/type",PROPERTY_HINT_ENUM,argt));
+			p_list->push_back(PropertyInfo(Variant::STRING,"argument/"+itos(i+1)+"/name"));
+		}
+	}
+
+public:
+
+
+	void edit(const StringName& p_sig) {
+
+		sig=p_sig;
+		_change_notify();
+	}
+
+	VisualScriptEditorSignalEdit() { undo_redo=NULL; }
+};
+
+class VisualScriptEditorVariableEdit : public Object {
+
+	OBJ_TYPE(VisualScriptEditorVariableEdit,Object)
+
+	StringName var;
+public:
+	UndoRedo *undo_redo;
+	Ref<VisualScript> script;
+
+
+protected:
+
+	static void _bind_methods() {
+		ObjectTypeDB::bind_method("_var_changed",&VisualScriptEditorVariableEdit::_var_changed);
+		ObjectTypeDB::bind_method("_var_value_changed",&VisualScriptEditorVariableEdit::_var_value_changed);
+	}
+
+	void _var_changed() {
+
+		_change_notify();
+	}
+	void _var_value_changed() {
+
+		_change_notify("value"); //so the whole tree is not redrawn, makes editing smoother in general
+	}
+
+	bool _set(const StringName& p_name, const Variant& p_value) {
+
+		if (var==StringName())
+			return false;
+
+
+
+		if (String(p_name)=="value") {
+			undo_redo->create_action("Set Variable Default Value");
+			Variant current=script->get_variable_default_value(var);
+			undo_redo->add_do_method(script.ptr(),"set_variable_default_value",var,p_value);
+			undo_redo->add_undo_method(script.ptr(),"set_variable_default_value",var,current);
+			undo_redo->add_do_method(this,"_var_value_changed");
+			undo_redo->add_undo_method(this,"_var_value_changed");
+			undo_redo->commit_action();
+			return true;
+		}
+
+		Dictionary d = script->call("get_variable_info",var);
+
+		if (String(p_name)=="type") {
+
+			Dictionary dc=d.copy();
+			dc["type"]=p_value;
+			undo_redo->create_action("Set Variable Type");
+			undo_redo->add_do_method(script.ptr(),"set_variable_info",var,dc);
+			undo_redo->add_undo_method(script.ptr(),"set_variable_info",var,d);
+			undo_redo->add_do_method(this,"_var_changed");
+			undo_redo->add_undo_method(this,"_var_changed");
+			undo_redo->commit_action();
+			return true;
+		}
+
+		if (String(p_name)=="hint") {
+
+			Dictionary dc=d.copy();
+			dc["hint"]=p_value;
+			undo_redo->create_action("Set Variable Type");
+			undo_redo->add_do_method(script.ptr(),"set_variable_info",var,dc);
+			undo_redo->add_undo_method(script.ptr(),"set_variable_info",var,d);
+			undo_redo->add_do_method(this,"_var_changed");
+			undo_redo->add_undo_method(this,"_var_changed");
+			undo_redo->commit_action();
+			return true;
+		}
+
+		if (String(p_name)=="hint_string") {
+
+			Dictionary dc=d.copy();
+			dc["hint_string"]=p_value;
+			undo_redo->create_action("Set Variable Type");
+			undo_redo->add_do_method(script.ptr(),"set_variable_info",var,dc);
+			undo_redo->add_undo_method(script.ptr(),"set_variable_info",var,d);
+			undo_redo->add_do_method(this,"_var_changed");
+			undo_redo->add_undo_method(this,"_var_changed");
+			undo_redo->commit_action();
+			return true;
+		}
+
+
+		return false;
+	}
+
+	bool _get(const StringName& p_name,Variant &r_ret) const {
+
+		if (var==StringName())
+			return false;
+
+		if (String(p_name)=="value") {
+			r_ret=script->get_variable_default_value(var);
+			return true;
+		}
+
+		PropertyInfo pinfo = script->get_variable_info(var);
+
+		if (String(p_name)=="type") {
+			r_ret=pinfo.type;
+			return true;
+		}
+		if (String(p_name)=="hint") {
+			r_ret=pinfo.hint;
+			return true;
+		}
+		if (String(p_name)=="hint_string") {
+			r_ret=pinfo.hint_string;
+			return true;
+		}
+
+		return false;
+	}
+	void _get_property_list( List<PropertyInfo> *p_list) const {
+
+		if (var==StringName())
+			return;
+
+		String argt="Variant";
+		for(int i=1;i<Variant::VARIANT_MAX;i++) {
+			argt+=","+Variant::get_type_name(Variant::Type(i));
+		}
+		p_list->push_back(PropertyInfo(Variant::INT,"type",PROPERTY_HINT_ENUM,argt));
+		p_list->push_back(PropertyInfo(script->get_variable_info(var).type,"value",script->get_variable_info(var).hint,script->get_variable_info(var).hint_string,PROPERTY_USAGE_DEFAULT));
+		p_list->push_back(PropertyInfo(Variant::INT,"hint",PROPERTY_HINT_ENUM,"None,Range,ExpRange,Enum,ExpEasing,Length,SpriteFrame,KeyAccel,BitFlags,AllFlags,File,Dir,GlobalFile,GlobalDir,ResourceType,MultilineText"));
+		p_list->push_back(PropertyInfo(Variant::STRING,"hint_string"));
+
+	}
+
+public:
+
+
+	void edit(const StringName& p_var) {
+
+		var=p_var;
+		_change_notify();
+	}
+
+	VisualScriptEditorVariableEdit() { undo_redo=NULL; }
+};
+
+static Color _color_from_type(Variant::Type p_type) {
+
+	Color color;
+	color.set_hsv(p_type/float(Variant::VARIANT_MAX),0.7,0.7);
+	return color;
+}
+
+
+
+void VisualScriptEditor::_update_graph_connections() {
+
+	graph->clear_connections();
+
+	List<VisualScript::SequenceConnection> sequence_conns;
+	script->get_sequence_connection_list(edited_func,&sequence_conns);
+
+
+	for (List<VisualScript::SequenceConnection>::Element *E=sequence_conns.front();E;E=E->next()) {
+
+		graph->connect_node(itos(E->get().from_node),E->get().from_output,itos(E->get().to_node),0);
+	}
+
+	List<VisualScript::DataConnection> data_conns;
+	script->get_data_connection_list(edited_func,&data_conns);
+
+	for (List<VisualScript::DataConnection>::Element *E=data_conns.front();E;E=E->next()) {
+
+		VisualScript::DataConnection dc=E->get();
+
+
+		Ref<VisualScriptNode> from_node = script->get_node(edited_func,E->get().from_node);
+		Ref<VisualScriptNode> to_node = script->get_node(edited_func,E->get().to_node);
+
+		if (to_node->has_input_sequence_port()) {
+			dc.to_port++;
+		}
+
+		dc.from_port+=from_node->get_output_sequence_port_count();
+
+		graph->connect_node(itos(E->get().from_node),dc.from_port,itos(E->get().to_node),dc.to_port);
+	}
+
+}
+
+
+void VisualScriptEditor::_update_graph(int p_only_id) {
+
+
+	//byebye all nodes
+	if (p_only_id>=0) {
+		if (graph->has_node(itos(p_only_id))) {
+			Node* gid = graph->get_node(itos(p_only_id));
+			if (gid)
+				memdelete(gid);
+		}
+	} else {
+
+		for(int i=0;i<graph->get_child_count();i++) {
+
+			if (graph->get_child(i)->cast_to<GraphNode>()) {
+				memdelete(graph->get_child(i));
+				i--;
+			}
+		}
+	}
+
+	if (!script->has_function(edited_func))
+		return;
+
+	Ref<Texture> type_icons[Variant::VARIANT_MAX]={
+		Control::get_icon("MiniVariant","EditorIcons"),
+		Control::get_icon("MiniBoolean","EditorIcons"),
+		Control::get_icon("MiniInteger","EditorIcons"),
+		Control::get_icon("MiniFloat","EditorIcons"),
+		Control::get_icon("MiniString","EditorIcons"),
+		Control::get_icon("MiniVector2","EditorIcons"),
+		Control::get_icon("MiniRect2","EditorIcons"),
+		Control::get_icon("MiniVector3","EditorIcons"),
+		Control::get_icon("MiniMatrix2","EditorIcons"),
+		Control::get_icon("MiniPlane","EditorIcons"),
+		Control::get_icon("MiniQuat","EditorIcons"),
+		Control::get_icon("MiniAabb","EditorIcons"),
+		Control::get_icon("MiniMatrix3","EditorIcons"),
+		Control::get_icon("MiniTransform","EditorIcons"),
+		Control::get_icon("MiniColor","EditorIcons"),
+		Control::get_icon("MiniImage","EditorIcons"),
+		Control::get_icon("MiniPath","EditorIcons"),
+		Control::get_icon("MiniRid","EditorIcons"),
+		Control::get_icon("MiniObject","EditorIcons"),
+		Control::get_icon("MiniInput","EditorIcons"),
+		Control::get_icon("MiniDictionary","EditorIcons"),
+		Control::get_icon("MiniArray","EditorIcons"),
+		Control::get_icon("MiniRawArray","EditorIcons"),
+		Control::get_icon("MiniIntArray","EditorIcons"),
+		Control::get_icon("MiniFloatArray","EditorIcons"),
+		Control::get_icon("MiniStringArray","EditorIcons"),
+		Control::get_icon("MiniVector2Array","EditorIcons"),
+		Control::get_icon("MiniVector3Array","EditorIcons"),
+		Control::get_icon("MiniColorArray","EditorIcons")
+	};
+
+
+
+	Ref<Texture> seq_port = Control::get_icon("VisualShaderPort","EditorIcons");
+
+	List<int> ids;
+	script->get_node_list(edited_func,&ids);
+	StringName editor_icons="EditorIcons";
+
+	for(List<int>::Element *E=ids.front();E;E=E->next()) {
+
+		if (p_only_id>=0 && p_only_id!=E->get())
+			continue;
+
+		Ref<VisualScriptNode> node = script->get_node(edited_func,E->get());
+		Vector2 pos = script->get_node_pos(edited_func,E->get());
+
+		GraphNode *gnode = memnew( GraphNode );
+		gnode->set_title(node->get_caption());
+
+		gnode->set_meta("__vnode",node);
+		gnode->set_name(itos(E->get()));
+		gnode->connect("dragged",this,"_node_moved",varray(E->get()));
+		gnode->connect("close_request",this,"_remove_node",varray(E->get()),CONNECT_DEFERRED);
+
+
+		if (E->get()!=script->get_function_node_id(edited_func)) {
+			//function can't be erased
+			gnode->set_show_close_button(true);
+		}
+
+		Label *text = memnew( Label );
+		text->set_text(node->get_text());
+		gnode->add_child(text);
+
+		int slot_idx=0;
+
+		bool single_seq_output = node->get_output_sequence_port_count()==1 && node->get_output_sequence_port_text(0)==String();
+		gnode->set_slot(0,node->has_input_sequence_port(),TYPE_SEQUENCE,Color(1,1,1,1),single_seq_output,TYPE_SEQUENCE,Color(1,1,1,1),seq_port,seq_port);
+		gnode->set_offset(pos*EDSCALE);
+		slot_idx++;
+
+		if (!single_seq_output) {
+			for(int i=0;i<node->get_output_sequence_port_count();i++) {
+
+				Label *text2 = memnew( Label );
+				text2->set_text(node->get_output_sequence_port_text(i));
+				text2->set_align(Label::ALIGN_RIGHT);
+				gnode->add_child(text2);
+				gnode->set_slot(slot_idx,false,0,Color(),true,TYPE_SEQUENCE,Color(1,1,1,1),seq_port,seq_port);
+				slot_idx++;
+			}
+		}
+
+		for(int i=0;i<MAX(node->get_output_value_port_count(),node->get_input_value_port_count());i++) {
+
+			bool left_ok=false;
+			Variant::Type left_type=Variant::NIL;
+			String left_name;
+
+			if (i<node->get_input_value_port_count()) {
+				PropertyInfo pi = node->get_input_value_port_info(i);
+				left_ok=true;
+				left_type=pi.type;
+				left_name=pi.name;
+			}
+
+			bool right_ok=false;
+			Variant::Type right_type=Variant::NIL;
+			String right_name;
+
+			if (i<node->get_output_value_port_count()) {
+				PropertyInfo pi = node->get_output_value_port_info(i);
+				right_ok=true;
+				right_type=pi.type;
+				right_name=pi.name;
+			}
+
+			HBoxContainer *hbc = memnew( HBoxContainer);
+
+			if (left_ok) {
+
+				Ref<Texture> t;
+				if (left_type>=0 && left_type<Variant::VARIANT_MAX) {
+					t=type_icons[left_type];
+				}
+				if (t.is_valid()) {
+					TextureFrame *tf = memnew(TextureFrame);
+					tf->set_texture(t);
+					tf->set_stretch_mode(TextureFrame::STRETCH_KEEP_CENTERED);
+					hbc->add_child(tf);
+				}
+
+				hbc->add_child(memnew(Label(left_name)));
+			} else {
+				Control *c = memnew(Control);
+				c->set_custom_minimum_size(Size2(10,0)*EDSCALE);
+				hbc->add_child(c);
+			}
+
+			hbc->add_spacer();
+
+			if (right_ok) {
+
+				hbc->add_child(memnew(Label(right_name)));
+
+				Ref<Texture> t;
+				if (right_type>=0 && right_type<Variant::VARIANT_MAX) {
+					t=type_icons[right_type];
+				}
+				if (t.is_valid()) {
+					TextureFrame *tf = memnew(TextureFrame);
+					tf->set_texture(t);
+					tf->set_stretch_mode(TextureFrame::STRETCH_KEEP_CENTERED);
+					hbc->add_child(tf);
+				}
+
+			}
+
+			gnode->add_child(hbc);
+
+			gnode->set_slot(slot_idx,left_ok,left_type,_color_from_type(left_type),right_ok,right_type,_color_from_type(right_type));
+
+			slot_idx++;
+		}
+
+		graph->add_child(gnode);
+	}
+
+	_update_graph_connections();
+
+}
+
+void VisualScriptEditor::_update_members() {
+
+
+	updating_members=true;
+
+	members->clear();
+	TreeItem *root = members->create_item();
+
+	TreeItem *functions = members->create_item(root);
+	functions->set_selectable(0,false);
+	functions->set_text(0,TTR("Functions:"));
+	functions->add_button(0,Control::get_icon("Override","EditorIcons"),1);
+	functions->add_button(0,Control::get_icon("Add","EditorIcons"),0);
+	functions->set_custom_bg_color(0,Control::get_color("prop_section","Editor"));
+
+	List<StringName> func_names;
+	script->get_function_list(&func_names);
+	for (List<StringName>::Element *E=func_names.front();E;E=E->next()) {
+		TreeItem *ti = members->create_item(functions)		;
+		ti->set_text(0,E->get());
+		ti->set_selectable(0,true);
+		ti->set_editable(0,true);
+		//ti->add_button(0,Control::get_icon("Edit","EditorIcons"),0); function arguments are in the node now
+		ti->add_button(0,Control::get_icon("Del","EditorIcons"),1);
+		ti->set_metadata(0,E->get());
+		if (selected==E->get())
+			ti->select(0);
+	}
+
+	TreeItem *variables = members->create_item(root);
+	variables->set_selectable(0,false);
+	variables->set_text(0,TTR("Variables:"));
+	variables->add_button(0,Control::get_icon("Add","EditorIcons"));
+	variables->set_custom_bg_color(0,Control::get_color("prop_section","Editor"));
+
+
+	List<StringName> var_names;
+	script->get_variable_list(&var_names);
+	for (List<StringName>::Element *E=var_names.front();E;E=E->next()) {
+		TreeItem *ti = members->create_item(variables)		;
+		ti->set_text(0,E->get());
+		ti->set_selectable(0,true);
+		ti->set_editable(0,true);
+		ti->add_button(0,Control::get_icon("Edit","EditorIcons"),0);
+		ti->add_button(0,Control::get_icon("Del","EditorIcons"),1);
+		ti->set_metadata(0,E->get());
+		if (selected==E->get())
+			ti->select(0);
+	}
+
+	TreeItem *_signals = members->create_item(root);
+	_signals->set_selectable(0,false);
+	_signals->set_text(0,TTR("Signals:"));
+	_signals->add_button(0,Control::get_icon("Add","EditorIcons"));
+	_signals->set_custom_bg_color(0,Control::get_color("prop_section","Editor"));
+
+	List<StringName> signal_names;
+	script->get_custom_signal_list(&signal_names);
+	for (List<StringName>::Element *E=signal_names.front();E;E=E->next()) {
+		TreeItem *ti = members->create_item(_signals)		;
+		ti->set_text(0,E->get());
+		ti->set_selectable(0,true);
+		ti->set_editable(0,true);
+		ti->add_button(0,Control::get_icon("Edit","EditorIcons"),0);
+		ti->add_button(0,Control::get_icon("Del","EditorIcons"),1);
+		ti->set_metadata(0,E->get());
+		if (selected==E->get())
+			ti->select(0);
+	}
+
+	String base_type=script->get_instance_base_type();
+	String icon_type=base_type;
+	if (!Control::has_icon(base_type,"EditorIcons")) {
+		icon_type="Object";
+	}
+
+	base_type_select->set_text(base_type);
+	base_type_select->set_icon(Control::get_icon(icon_type,"EditorIcons"));
+
+	updating_members=false;
+
+}
+
+void VisualScriptEditor::_member_selected() {
+
+	if (updating_members)
+		return;
+
+	TreeItem *ti=members->get_selected();
+	ERR_FAIL_COND(!ti);
+
+
+	selected=ti->get_metadata(0);
+//	print_line("selected: "+String(selected));
+
+
+	if (ti->get_parent()==members->get_root()->get_children()) {
+
+		if (edited_func!=selected) {
+
+			revert_on_drag=edited_func;
+			edited_func=selected;
+			_update_graph();
+		}
+
+		return; //or crash because it will become invalid
+
+	}
+
+
+
+}
+
+void VisualScriptEditor::_member_edited() {
+
+	if (updating_members)
+		return;
+
+	TreeItem *ti=members->get_edited();
+	ERR_FAIL_COND(!ti);
+
+	String name = ti->get_metadata(0);
+	String new_name = ti->get_text(0);
+
+	if (name==new_name)
+		return;
+
+	if (!new_name.is_valid_identifier()) {
+
+		EditorNode::get_singleton()->show_warning(TTR("Name is not a valid identifier: ")+new_name);
+		updating_members=true;
+		ti->set_text(0,name);
+		updating_members=false;
+		return;
+
+	}
+
+	if (script->has_function(new_name) || script->has_variable(new_name) || script->has_custom_signal(new_name)) {
+
+		EditorNode::get_singleton()->show_warning(TTR("Name already in use by another func/var/signal: ")+new_name);
+		updating_members=true;
+		ti->set_text(0,name);
+		updating_members=false;
+		return;
+	}
+
+	TreeItem *root=members->get_root();
+
+	if (ti->get_parent()==root->get_children()) {
+
+		if (edited_func==selected) {
+			edited_func=new_name;
+		}
+		selected=new_name;
+
+
+		_update_graph();
+
+		undo_redo->create_action(TTR("Rename Function"));
+		undo_redo->add_do_method(script.ptr(),"rename_function",name,new_name);
+		undo_redo->add_undo_method(script.ptr(),"rename_function",new_name,name);
+		undo_redo->add_do_method(this,"_update_members");
+		undo_redo->add_undo_method(this,"_update_members");
+		undo_redo->commit_action();
+
+		return; //or crash because it will become invalid
+
+	}
+
+	if (ti->get_parent()==root->get_children()->get_next()) {
+
+		selected=new_name;
+		undo_redo->create_action(TTR("Rename Variable"));
+		undo_redo->add_do_method(script.ptr(),"rename_variable",name,new_name);
+		undo_redo->add_undo_method(script.ptr(),"rename_variable",new_name,name);
+		undo_redo->add_do_method(this,"_update_members");
+		undo_redo->add_undo_method(this,"_update_members");
+		undo_redo->commit_action();
+
+		return; //or crash because it will become invalid
+	}
+
+	if (ti->get_parent()==root->get_children()->get_next()->get_next()) {
+
+		selected=new_name;
+		undo_redo->create_action(TTR("Rename Signal"));
+		undo_redo->add_do_method(script.ptr(),"rename_custom_signal",name,new_name);
+		undo_redo->add_undo_method(script.ptr(),"rename_custom_signal",new_name,name);
+		undo_redo->add_do_method(this,"_update_members");
+		undo_redo->add_undo_method(this,"_update_members");
+		undo_redo->commit_action();
+
+		return; //or crash because it will become invalid
+	}
+}
+
+void VisualScriptEditor::_override_pressed(int p_id) {
+
+	//override a virtual function or method from base type
+
+	ERR_FAIL_COND(!virtuals_in_menu.has(p_id));
+
+	VirtualInMenu vim=virtuals_in_menu[p_id];
+
+	String name = _validate_name(vim.name);
+	selected=name;
+	edited_func=selected;
+	Ref<VisualScriptFunction> func_node;
+	func_node.instance();
+	func_node->set_name(vim.name);
+
+	undo_redo->create_action(TTR("Add Function"));
+	undo_redo->add_do_method(script.ptr(),"add_function",name);
+	for(int i=0;i<vim.args.size();i++) {
+		func_node->add_argument(vim.args[i].first,vim.args[i].second);
+	}
+
+
+	undo_redo->add_do_method(script.ptr(),"add_node",name,script->get_available_id(),func_node);
+	if (vim.ret!=Variant::NIL || vim.ret_variant) {
+		Ref<VisualScriptReturn> ret_node;
+		ret_node.instance();
+		ret_node->set_return_type(vim.ret);
+		ret_node->set_enable_return_value(true);
+		ret_node->set_name(vim.name);
+		undo_redo->add_do_method(script.ptr(),"add_node",name,script->get_available_id()+1,ret_node,Vector2(500,0));
+
+	}
+
+	undo_redo->add_undo_method(script.ptr(),"remove_function",name);
+	undo_redo->add_do_method(this,"_update_members");
+	undo_redo->add_undo_method(this,"_update_members");
+	undo_redo->commit_action();
+
+
+	_update_graph();
+}
+
+void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_button) {
+
+	TreeItem *ti=p_item->cast_to<TreeItem>();
+
+	TreeItem *root=members->get_root();
+
+	if (ti->get_parent()==root) {
+		//main buttons
+		if (ti==root->get_children()) {
+			//add function, this one uses menu
+
+			if (p_button==1) {
+				new_function_menu->clear();
+				new_function_menu->set_size(Size2(0,0));
+				int idx=0;
+
+				virtuals_in_menu.clear();
+
+				List<MethodInfo> mi;
+				ObjectTypeDB::get_method_list(script->get_instance_base_type(),&mi);
+				for (List<MethodInfo>::Element *E=mi.front();E;E=E->next()) {
+					MethodInfo mi=E->get();
+					if (mi.flags&METHOD_FLAG_VIRTUAL) {
+
+						VirtualInMenu vim;
+						vim.name=mi.name;
+						vim.ret=mi.return_val.type;
+						if (mi.return_val.name!=String())
+							vim.ret_variant=true;
+						else
+							vim.ret_variant=false;
+
+						String desc;
+
+						if (mi.return_val.type==Variant::NIL)
+							desc="var";
+						else
+							desc=Variant::get_type_name(mi.return_val.type);
+						desc+=" "+mi.name+" ( ";
+
+
+						for(int i=0;i<mi.arguments.size();i++) {
+
+							if (i>0)
+								desc+=", ";
+
+							if (mi.arguments[i].type==Variant::NIL)
+								desc+="var ";
+							else
+								desc+=Variant::get_type_name(mi.arguments[i].type)+" ";
+
+							desc+=mi.arguments[i].name;
+
+							Pair<Variant::Type,String> p;
+							p.first=mi.arguments[i].type;
+							p.second=mi.arguments[i].name;
+							vim.args.push_back( p );
+
+						}
+
+						desc+=" )";
+
+						virtuals_in_menu[idx]=vim;
+
+						new_function_menu->add_item(desc,idx);
+						idx++;
+					}
+				}
+
+				Rect2 pos = members->get_item_rect(ti);
+				new_function_menu->set_pos(members->get_global_pos()+pos.pos+Vector2(0,pos.size.y));
+				new_function_menu->popup();
+				return;
+			} else if (p_button==0) {
+
+
+				String name = _validate_name("new_function");
+				selected=name;
+				edited_func=selected;
+
+				Ref<VisualScriptFunction> func_node;
+				func_node.instance();
+				func_node->set_name(name);
+
+				undo_redo->create_action(TTR("Add Function"));
+				undo_redo->add_do_method(script.ptr(),"add_function",name);
+				undo_redo->add_do_method(script.ptr(),"add_node",name,script->get_available_id(),func_node);
+				undo_redo->add_undo_method(script.ptr(),"remove_function",name);
+				undo_redo->add_do_method(this,"_update_members");
+				undo_redo->add_undo_method(this,"_update_members");
+				undo_redo->commit_action();
+
+				_update_graph();
+			}
+
+			return; //or crash because it will become invalid
+
+		}
+
+		if (ti==root->get_children()->get_next()) {
+			//add variable
+			String name = _validate_name("new_variable");
+			selected=name;
+
+			undo_redo->create_action(TTR("Add Variable"));
+			undo_redo->add_do_method(script.ptr(),"add_variable",name);
+			undo_redo->add_undo_method(script.ptr(),"remove_variable",name);
+			undo_redo->add_do_method(this,"_update_members");
+			undo_redo->add_undo_method(this,"_update_members");
+			undo_redo->commit_action();
+			return; //or crash because it will become invalid
+
+		}
+
+		if (ti==root->get_children()->get_next()->get_next()) {
+			//add variable
+			String name = _validate_name("new_signal");
+			selected=name;
+
+			undo_redo->create_action(TTR("Add Signal"));
+			undo_redo->add_do_method(script.ptr(),"add_custom_signal",name);
+			undo_redo->add_undo_method(script.ptr(),"remove_custom_signal",name);
+			undo_redo->add_do_method(this,"_update_members");
+			undo_redo->add_undo_method(this,"_update_members");
+			undo_redo->commit_action();
+			return; //or crash because it will become invalid
+
+		}
+
+	} else {
+
+		if (ti->get_parent()==root->get_children()) {
+			//edit/remove function
+			String name = ti->get_metadata(0);
+
+			if (p_button==1) {
+				//delete the function
+				undo_redo->create_action(TTR("Remove Function"));
+				undo_redo->add_do_method(script.ptr(),"remove_function",name);
+				undo_redo->add_undo_method(script.ptr(),"add_function",name);
+				List<int> nodes;
+				script->get_node_list(name,&nodes);
+				for (List<int>::Element *E=nodes.front();E;E=E->next()) {
+					undo_redo->add_undo_method(script.ptr(),"add_node",name,E->get(),script->get_node(name,E->get()),script->get_node_pos(name,E->get()));
+				}
+
+				List<VisualScript::SequenceConnection> seq_connections;
+
+				script->get_sequence_connection_list(name,&seq_connections);
+
+				for (List<VisualScript::SequenceConnection>::Element *E=seq_connections.front();E;E=E->next()) {
+					undo_redo->add_undo_method(script.ptr(),"sequence_connect",name,E->get().from_node,E->get().from_output,E->get().to_node);
+				}
+
+				List<VisualScript::DataConnection> data_connections;
+
+				script->get_data_connection_list(name,&data_connections);
+
+				for (List<VisualScript::DataConnection>::Element *E=data_connections.front();E;E=E->next()) {
+					undo_redo->add_undo_method(script.ptr(),"data_connect",name,E->get().from_node,E->get().from_port,E->get().to_node,E->get().to_port);
+				}
+
+				//for(int i=0;i<script->function_get_argument_count(name);i++) {
+				////	undo_redo->add_undo_method(script.ptr(),"function_add_argument",name,script->function_get_argument_name(name,i),script->function_get_argument_type(name,i));
+				//}
+				undo_redo->add_do_method(this,"_update_members");
+				undo_redo->add_undo_method(this,"_update_members");
+				undo_redo->commit_action();
+
+			} else if (p_button==0) {
+
+			}
+			return; //or crash because it will become invalid
+
+		}
+
+		if (ti->get_parent()==root->get_children()->get_next()) {
+			//edit/remove variable
+
+			String name = ti->get_metadata(0);
+
+			if (p_button==1) {
+
+
+				undo_redo->create_action(TTR("Remove Variable"));
+				undo_redo->add_do_method(script.ptr(),"remove_variable",name);
+				undo_redo->add_undo_method(script.ptr(),"add_variable",name,script->get_variable_default_value(name));
+				undo_redo->add_undo_method(script.ptr(),"set_variable_info",name,script->call("get_variable_info",name)); //return as dict
+				undo_redo->add_do_method(this,"_update_members");
+				undo_redo->add_undo_method(this,"_update_members");
+				undo_redo->commit_action();
+				return; //or crash because it will become invalid
+			} else if (p_button==0) {
+
+				variable_editor->edit(name);
+				edit_variable_dialog->set_title(TTR("Editing Variable: ")+name);
+				edit_variable_dialog->popup_centered_minsize(Size2(400,200)*EDSCALE);
+			}
+
+		}
+
+		if (ti->get_parent()==root->get_children()->get_next()->get_next()) {
+			//edit/remove variable
+			String name = ti->get_metadata(0);
+
+			if (p_button==1) {
+
+				undo_redo->create_action(TTR("Remove Signal"));
+				undo_redo->add_do_method(script.ptr(),"remove_custom_signal",name);
+				undo_redo->add_undo_method(script.ptr(),"add_custom_signal",name);
+
+				for(int i=0;i<script->custom_signal_get_argument_count(name);i++) {
+					undo_redo->add_undo_method(script.ptr(),"custom_signal_add_argument",name,script->custom_signal_get_argument_name(name,i),script->custom_signal_get_argument_type(name,i));
+				}
+
+				undo_redo->add_do_method(this,"_update_members");
+				undo_redo->add_undo_method(this,"_update_members");
+				undo_redo->commit_action();
+			} else if (p_button==0) {
+
+				signal_editor->edit(name);
+				edit_signal_dialog->set_title(TTR("Editing Signal: ")+name);
+				edit_signal_dialog->popup_centered_minsize(Size2(400,300)*EDSCALE);
+			}
+
+			return; //or crash because it will become invalid
+
+		}
+
+
+	}
+}
+
+void VisualScriptEditor::_available_node_doubleclicked() {
+
+	TreeItem *item = nodes->get_selected();
+
+	if (!item)
+		return;
+
+	String which = item->get_metadata(0);
+	if (which==String())
+		return;
+
+	Vector2 ofs = graph->get_scroll_ofs() + graph->get_size() * 0.5;
+	ofs/=EDSCALE;
+
+	while(true) {
+		bool exists=false;
+		List<int> existing;
+		script->get_node_list(edited_func,&existing);
+		for (List<int>::Element *E=existing.front();E;E=E->next()) {
+			Point2 pos = script->get_node_pos(edited_func,E->get());
+			if (pos.distance_to(ofs)<15) {
+				ofs+=Vector2(25,25);
+				exists=true;
+				break;
+			}
+		}
+
+		if (exists)
+			continue;
+		break;
+
+	}
+
+
+	Ref<VisualScriptNode> vnode = VisualScriptLanguage::singleton->create_node_from_name(which);
+	int new_id = script->get_available_id();
+
+	undo_redo->create_action(TTR("Add Node"));
+	undo_redo->add_do_method(script.ptr(),"add_node",edited_func,new_id,vnode,ofs);
+	undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id);
+	undo_redo->add_do_method(this,"_update_graph");
+	undo_redo->add_undo_method(this,"_update_graph");
+	undo_redo->commit_action();
+
+	Node* node = graph->get_node(itos(new_id));
+	if (node) {
+		graph->set_selected(node);
+		_node_selected(node);
+	}
+
+}
+
+void VisualScriptEditor::_update_available_nodes() {
+
+	nodes->clear();
+
+	TreeItem *root = nodes->create_item();
+
+	Map<String,TreeItem*> path_cache;
+
+	List<String> fnodes;
+	VisualScriptLanguage::singleton->get_registered_node_names(&fnodes);
+
+	for (List<String>::Element *E=fnodes.front();E;E=E->next()) {
+
+		Vector<String> path = E->get().split("/");
+		String sp;
+		TreeItem* parent=root;
+
+		for(int i=0;i<path.size()-1;i++) {
+
+			if (i>0)
+				sp+=",";
+			sp+=path[i];
+			if (!path_cache.has(sp)) {
+				TreeItem* pathn = nodes->create_item(parent);
+				pathn->set_selectable(0,false);
+				pathn->set_text(0,path[i].capitalize());
+				path_cache[sp]=pathn;
+				parent=pathn;
+				pathn->set_collapsed(true); //should remember state
+			} else {
+				parent=path_cache[sp];
+			}
+		}
+
+		TreeItem *item = nodes->create_item(parent);
+		item->set_text(0,path[path.size()-1].capitalize());
+		item->set_selectable(0,true);
+		item->set_metadata(0,E->get());
+	}
+
+}
+
+String VisualScriptEditor::_validate_name(const String& p_name) const {
+
+	String valid=p_name;
+
+	int counter=1;
+	while(true) {
+
+		bool exists = script->has_function(valid) || script->has_variable(valid) || script->has_custom_signal(valid);
+
+		if (exists) {
+			counter++;
+			valid=p_name+"_"+itos(counter);
+			continue;
+		}
+
+		break;
+	}
+
+	return valid;
+}
+
+void VisualScriptEditor::_on_nodes_delete() {
+
+
+	List<int> to_erase;
+
+	for(int i=0;i<graph->get_child_count();i++) {
+		GraphNode *gn = graph->get_child(i)->cast_to<GraphNode>();
+		if (gn) {
+			if (gn->is_selected() && gn->is_close_button_visible()) {
+				to_erase.push_back(gn->get_name().operator String().to_int());
+			}
+		}
+	}
+
+	if (to_erase.empty())
+		return;
+
+	undo_redo->create_action("Remove VisualScript Nodes");
+
+	for(List<int>::Element*F=to_erase.front();F;F=F->next()) {
+
+
+		undo_redo->add_do_method(script.ptr(),"remove_node",edited_func,F->get());
+		undo_redo->add_undo_method(script.ptr(),"add_node",edited_func,F->get(),script->get_node(edited_func,F->get()),script->get_node_pos(edited_func,F->get()));
+
+
+		List<VisualScript::SequenceConnection> sequence_conns;
+		script->get_sequence_connection_list(edited_func,&sequence_conns);
+
+
+		for (List<VisualScript::SequenceConnection>::Element *E=sequence_conns.front();E;E=E->next()) {
+
+			if (E->get().from_node==F->get() || E->get().to_node==F->get()) {
+				undo_redo->add_undo_method(script.ptr(),"sequence_connect",edited_func,E->get().from_node,E->get().from_output,E->get().to_node);
+			}
+		}
+
+		List<VisualScript::DataConnection> data_conns;
+		script->get_data_connection_list(edited_func,&data_conns);
+
+		for (List<VisualScript::DataConnection>::Element *E=data_conns.front();E;E=E->next()) {
+
+			if (E->get().from_node==F->get() || E->get().to_node==F->get()) {
+				undo_redo->add_undo_method(script.ptr(),"data_connect",edited_func,E->get().from_node,E->get().from_port,E->get().to_node,E->get().to_port);
+			}
+		}
+
+	}
+	undo_redo->add_do_method(this,"_update_graph");
+	undo_redo->add_undo_method(this,"_update_graph");
+
+	undo_redo->commit_action();
+}
+
+
+void VisualScriptEditor::_on_nodes_duplicate() {
+
+
+	List<int> to_duplicate;
+
+	for(int i=0;i<graph->get_child_count();i++) {
+		GraphNode *gn = graph->get_child(i)->cast_to<GraphNode>();
+		if (gn) {
+			if (gn->is_selected() && gn->is_close_button_visible()) {
+				to_duplicate.push_back(gn->get_name().operator String().to_int());
+			}
+		}
+	}
+
+	if (to_duplicate.empty())
+		return;
+
+	undo_redo->create_action("Duplicate VisualScript Nodes");
+	int idc=script->get_available_id()+1;
+
+	Set<int> to_select;
+
+	for(List<int>::Element*F=to_duplicate.front();F;F=F->next()) {
+
+		Ref<VisualScriptNode> node = script->get_node(edited_func,F->get());
+
+		Ref<VisualScriptNode> dupe = node->duplicate();
+
+		int new_id = idc++;
+		to_select.insert(new_id);
+		undo_redo->add_do_method(script.ptr(),"add_node",edited_func,new_id,dupe,script->get_node_pos(edited_func,F->get())+Vector2(20,20));
+		undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id);
+
+	}
+	undo_redo->add_do_method(this,"_update_graph");
+	undo_redo->add_undo_method(this,"_update_graph");
+
+	undo_redo->commit_action();
+
+	for(int i=0;i<graph->get_child_count();i++) {
+		GraphNode *gn = graph->get_child(i)->cast_to<GraphNode>();
+		if (gn) {
+			int id = gn->get_name().operator String().to_int();
+			gn->set_selected(to_select.has(id));
+
+		}
+	}
+
+	if (to_select.size()) {
+		EditorNode::get_singleton()->push_item(script->get_node(edited_func,to_select.front()->get()).ptr());
+	}
+
+}
+
+void VisualScriptEditor::_input(const InputEvent& p_event) {
+
+	if (p_event.type==InputEvent::MOUSE_BUTTON && !p_event.mouse_button.pressed && p_event.mouse_button.button_index==BUTTON_LEFT) {
+		revert_on_drag=String(); //so we can still drag functions
+	}
+}
+
+Variant VisualScriptEditor::get_drag_data_fw(const Point2& p_point,Control* p_from) {
+
+
+	if (p_from==nodes) {
+
+		TreeItem *it = nodes->get_item_at_pos(p_point);
+		if (!it)
+			return Variant();
+		String type=it->get_metadata(0);
+		if (type==String())
+			return Variant();
+
+		Dictionary dd;
+		dd["type"]="visual_script_node_drag";
+		dd["node_type"]=type;
+
+		Label *label = memnew(Label);
+		label->set_text(it->get_text(0));
+		set_drag_preview(label);
+		return dd;
+	}
+
+	if (p_from==members) {
+
+
+		TreeItem *it = members->get_item_at_pos(p_point);
+		if (!it)
+			return Variant();
+
+		String type=it->get_metadata(0);
+
+		if (type==String())
+			return Variant();
+
+
+		Dictionary dd;
+		TreeItem *root=members->get_root();
+
+		if (it->get_parent()==root->get_children()) {
+
+			dd["type"]="visual_script_function_drag";
+			dd["function"]=type;
+			if (revert_on_drag!=String()) {
+				edited_func=revert_on_drag; //revert so function does not change
+				revert_on_drag=String();
+				_update_graph();
+			}
+		} else if (it->get_parent()==root->get_children()->get_next()) {
+
+			dd["type"]="visual_script_variable_drag";
+			dd["variable"]=type;
+		} else if (it->get_parent()==root->get_children()->get_next()->get_next()) {
+
+			dd["type"]="visual_script_signal_drag";
+			dd["signal"]=type;
+
+		} else {
+			return Variant();
+		}
+
+
+
+
+
+
+		Label *label = memnew(Label);
+		label->set_text(it->get_text(0));
+		set_drag_preview(label);
+		return dd;
+	}
+	return Variant();
+}
+
+bool VisualScriptEditor::can_drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from) const{
+
+	if (p_from==graph) {
+
+		Dictionary d = p_data;
+		if (d.has("type") &&
+				(
+					String(d["type"])=="visual_script_node_drag" ||
+					String(d["type"])=="visual_script_function_drag" ||
+					String(d["type"])=="visual_script_variable_drag" ||
+					String(d["type"])=="visual_script_signal_drag"
+				) )
+				return true;
+	}
+
+
+	return false;
+}
+void VisualScriptEditor::drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from){
+
+	if (p_from==graph) {
+
+		Dictionary d = p_data;
+		if (d.has("type") && String(d["type"])=="visual_script_node_drag") {
+
+			Vector2 ofs = graph->get_scroll_ofs() + p_point;
+
+			ofs/=EDSCALE;
+
+			Ref<VisualScriptNode> vnode = VisualScriptLanguage::singleton->create_node_from_name(d["node_type"]);
+			int new_id = script->get_available_id();
+
+			undo_redo->create_action(TTR("Add Node"));
+			undo_redo->add_do_method(script.ptr(),"add_node",edited_func,new_id,vnode,ofs);
+			undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id);
+			undo_redo->add_do_method(this,"_update_graph");
+			undo_redo->add_undo_method(this,"_update_graph");
+			undo_redo->commit_action();
+
+			Node* node = graph->get_node(itos(new_id));
+			if (node) {
+				graph->set_selected(node);
+				_node_selected(node);
+			}
+		}
+
+		if (d.has("type") && String(d["type"])=="visual_script_variable_drag") {
+
+			Vector2 ofs = graph->get_scroll_ofs() + p_point;
+
+			ofs/=EDSCALE;
+
+			Ref<VisualScriptVariable> vnode;
+			vnode.instance();
+			vnode->set_variable(d["variable"]);
+
+			int new_id = script->get_available_id();
+
+			undo_redo->create_action(TTR("Add Node"));
+			undo_redo->add_do_method(script.ptr(),"add_node",edited_func,new_id,vnode,ofs);
+			undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id);
+			undo_redo->add_do_method(this,"_update_graph");
+			undo_redo->add_undo_method(this,"_update_graph");
+			undo_redo->commit_action();
+
+			Node* node = graph->get_node(itos(new_id));
+			if (node) {
+				graph->set_selected(node);
+				_node_selected(node);
+			}
+		}
+
+		if (d.has("type") && String(d["type"])=="visual_script_function_drag") {
+
+			Vector2 ofs = graph->get_scroll_ofs() + p_point;
+
+			ofs/=EDSCALE;
+
+			Ref<VisualScriptScriptCall> vnode;
+			vnode.instance();
+			vnode->set_call_mode(VisualScriptScriptCall::CALL_MODE_SELF);
+			vnode->set_function(d["function"]);
+
+			int new_id = script->get_available_id();
+
+			undo_redo->create_action(TTR("Add Node"));
+			undo_redo->add_do_method(script.ptr(),"add_node",edited_func,new_id,vnode,ofs);
+			undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id);
+			undo_redo->add_do_method(this,"_update_graph");
+			undo_redo->add_undo_method(this,"_update_graph");
+			undo_redo->commit_action();
+
+			Node* node = graph->get_node(itos(new_id));
+			if (node) {
+				graph->set_selected(node);
+				_node_selected(node);
+			}
+		}
+
+
+		if (d.has("type") && String(d["type"])=="visual_script_signal_drag") {
+
+			Vector2 ofs = graph->get_scroll_ofs() + p_point;
+
+			ofs/=EDSCALE;
+
+			Ref<VisualScriptEmitSignal> vnode;
+			vnode.instance();
+			vnode->set_signal(d["signal"]);
+
+			int new_id = script->get_available_id();
+
+			undo_redo->create_action(TTR("Add Node"));
+			undo_redo->add_do_method(script.ptr(),"add_node",edited_func,new_id,vnode,ofs);
+			undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id);
+			undo_redo->add_do_method(this,"_update_graph");
+			undo_redo->add_undo_method(this,"_update_graph");
+			undo_redo->commit_action();
+
+			Node* node = graph->get_node(itos(new_id));
+			if (node) {
+				graph->set_selected(node);
+				_node_selected(node);
+			}
+		}
+	}
+
+
+}
+
+
+/////////////////////////
+
+
+
+void VisualScriptEditor::apply_code() {
+
+
+}
+
+Ref<Script> VisualScriptEditor::get_edited_script() const{
+
+	return script;
+}
+
+Vector<String> VisualScriptEditor::get_functions(){
+
+	return Vector<String>();
+}
+
+void VisualScriptEditor::set_edited_script(const Ref<Script>& p_script){
+
+	script=p_script;
+	signal_editor->script=p_script;
+	signal_editor->undo_redo=undo_redo;
+	variable_editor->script=p_script;
+	variable_editor->undo_redo=undo_redo;
+
+
+	script->connect("node_ports_changed",this,"_node_ports_changed");
+
+	_update_members();
+	_update_available_nodes();
+}
+
+void VisualScriptEditor::reload_text(){
+
+
+}
+
+String VisualScriptEditor::get_name(){
+
+	String name;
+
+	if (script->get_path().find("local://")==-1 && script->get_path().find("::")==-1) {
+		name=script->get_path().get_file();
+		if (is_unsaved()) {
+			name+="(*)";
+		}
+	} else if (script->get_name()!="")
+		name=script->get_name();
+	else
+		name=script->get_type()+"("+itos(script->get_instance_ID())+")";
+
+	return name;
+
+}
+
+Ref<Texture> VisualScriptEditor::get_icon(){
+
+	return Control::get_icon("VisualScript","EditorIcons");
+}
+
+bool VisualScriptEditor::is_unsaved(){
+
+	return false;
+}
+
+Variant VisualScriptEditor::get_edit_state(){
+
+	return Variant();
+}
+
+void VisualScriptEditor::set_edit_state(const Variant& p_state){
+
+
+}
+
+void VisualScriptEditor::goto_line(int p_line){
+
+
+}
+
+void VisualScriptEditor::trim_trailing_whitespace(){
+
+
+}
+
+void VisualScriptEditor::ensure_focus(){
+
+
+}
+
+void VisualScriptEditor::tag_saved_version(){
+
+
+}
+
+void VisualScriptEditor::reload(bool p_soft){
+
+
+}
+
+void VisualScriptEditor::get_breakpoints(List<int> *p_breakpoints){
+
+
+}
+
+bool VisualScriptEditor::goto_method(const String& p_method){
+
+	return false;
+}
+
+void VisualScriptEditor::add_callback(const String& p_function,StringArray p_args){
+
+
+}
+
+void VisualScriptEditor::update_settings(){
+
+
+}
+
+
+void VisualScriptEditor::set_tooltip_request_func(String p_method,Object* p_obj){
+
+
+}
+
+Control *VisualScriptEditor::get_edit_menu(){
+
+	return NULL;
+}
+
+void VisualScriptEditor::_change_base_type() {
+
+	select_base_type->popup(true);
+}
+
+void VisualScriptEditor::_change_base_type_callback() {
+
+	String bt = select_base_type->get_selected_type();
+
+	ERR_FAIL_COND(bt==String());
+	undo_redo->create_action("Change Base Type");
+	undo_redo->add_do_method(script.ptr(),"set_instance_base_type",bt);
+	undo_redo->add_undo_method(script.ptr(),"set_instance_base_type",script->get_instance_base_type());
+	undo_redo->add_do_method(this,"_update_members");
+	undo_redo->add_undo_method(this,"_update_members");
+	undo_redo->commit_action();
+
+}
+
+void VisualScriptEditor::_node_selected(Node* p_node) {
+
+	Ref<VisualScriptNode> vnode = p_node->get_meta("__vnode");
+	if (vnode.is_null())
+		return;
+
+	EditorNode::get_singleton()->push_item(vnode.ptr());	//edit node in inspector
+}
+
+static bool _get_out_slot(const Ref<VisualScriptNode>& p_node,int p_slot,int& r_real_slot,bool& r_sequence) {
+
+	if (p_slot<p_node->get_output_sequence_port_count()) {
+		r_sequence=true;
+		r_real_slot=p_slot;
+
+		return true;
+	}
+
+	r_real_slot=p_slot-p_node->get_output_sequence_port_count();
+	r_sequence=false;
+
+	return (r_real_slot<p_node->get_output_value_port_count());
+
+}
+
+static bool _get_in_slot(const Ref<VisualScriptNode>& p_node,int p_slot,int& r_real_slot,bool& r_sequence) {
+
+	if (p_slot==0 && p_node->has_input_sequence_port()) {
+		r_sequence=true;
+		r_real_slot=0;
+		return true;
+	}
+
+
+	r_real_slot=p_slot-(p_node->has_input_sequence_port()?1:0);
+	r_sequence=false;
+
+	return r_real_slot<p_node->get_input_value_port_count();
+
+}
+
+
+void VisualScriptEditor::_begin_node_move() {
+
+	undo_redo->create_action("Move Node(s)");
+}
+
+void VisualScriptEditor::_end_node_move() {
+
+	undo_redo->commit_action();
+}
+
+void VisualScriptEditor::_move_node(String func,int p_id,const Vector2& p_to) {
+
+
+
+	if (func==String(edited_func)) {
+		Node* node = graph->get_node(itos(p_id));
+		if (node && node->cast_to<GraphNode>())
+			node->cast_to<GraphNode>()->set_offset(p_to);
+	}
+	script->set_node_pos(edited_func,p_id,p_to/EDSCALE);
+}
+
+void VisualScriptEditor::_node_moved(Vector2 p_from,Vector2 p_to, int p_id) {
+
+	undo_redo->add_do_method(this,"_move_node",String(edited_func),p_id,p_to);
+	undo_redo->add_undo_method(this,"_move_node",String(edited_func),p_id,p_from);
+}
+
+void VisualScriptEditor::_remove_node(int p_id) {
+
+
+	undo_redo->create_action("Remove VisualScript Node");
+
+	undo_redo->add_do_method(script.ptr(),"remove_node",edited_func,p_id);
+	undo_redo->add_undo_method(script.ptr(),"add_node",edited_func,p_id,script->get_node(edited_func,p_id),script->get_node_pos(edited_func,p_id));
+
+
+	List<VisualScript::SequenceConnection> sequence_conns;
+	script->get_sequence_connection_list(edited_func,&sequence_conns);
+
+
+	for (List<VisualScript::SequenceConnection>::Element *E=sequence_conns.front();E;E=E->next()) {
+
+		if (E->get().from_node==p_id || E->get().to_node==p_id) {
+			undo_redo->add_undo_method(script.ptr(),"sequence_connect",edited_func,E->get().from_node,E->get().from_output,E->get().to_node);
+		}
+	}
+
+	List<VisualScript::DataConnection> data_conns;
+	script->get_data_connection_list(edited_func,&data_conns);
+
+	for (List<VisualScript::DataConnection>::Element *E=data_conns.front();E;E=E->next()) {
+
+		if (E->get().from_node==p_id || E->get().to_node==p_id) {
+			undo_redo->add_undo_method(script.ptr(),"data_connect",edited_func,E->get().from_node,E->get().from_port,E->get().to_node,E->get().to_port);
+		}
+	}
+
+	undo_redo->add_do_method(this,"_update_graph");
+	undo_redo->add_undo_method(this,"_update_graph");
+
+	undo_redo->commit_action();
+}
+
+
+void VisualScriptEditor::_node_ports_changed(const String& p_func,int p_id) {
+
+	if (p_func!=String(edited_func))
+		return;
+
+	_update_graph(p_id);
+}
+
+void VisualScriptEditor::_graph_connected(const String& p_from,int p_from_slot,const String& p_to,int p_to_slot) {
+
+	Ref<VisualScriptNode> from_node = script->get_node(edited_func,p_from.to_int());
+	ERR_FAIL_COND(!from_node.is_valid());
+
+	bool from_seq;
+	int from_port;
+
+	if (!_get_out_slot(from_node,p_from_slot,from_port,from_seq))
+		return; //can't  connect this, it' s invalid
+
+	Ref<VisualScriptNode> to_node = script->get_node(edited_func,p_to.to_int());
+	ERR_FAIL_COND(!to_node.is_valid());
+
+	bool to_seq;
+	int to_port;
+
+	if (!_get_in_slot(to_node,p_to_slot,to_port,to_seq))
+		return; //can't  connect this, it' s invalid
+
+
+	ERR_FAIL_COND(from_seq!=to_seq);
+
+
+	undo_redo->create_action("Connect Nodes");
+
+	if (from_seq) {
+		undo_redo->add_do_method(script.ptr(),"sequence_connect",edited_func,p_from.to_int(),from_port,p_to.to_int());
+		undo_redo->add_undo_method(script.ptr(),"sequence_disconnect",edited_func,p_from.to_int(),from_port,p_to.to_int());
+	} else {
+		undo_redo->add_do_method(script.ptr(),"data_connect",edited_func,p_from.to_int(),from_port,p_to.to_int(),to_port);
+		undo_redo->add_undo_method(script.ptr(),"data_disconnect",edited_func,p_from.to_int(),from_port,p_to.to_int(),to_port);
+	}
+
+	undo_redo->add_do_method(this,"_update_graph_connections");
+	undo_redo->add_undo_method(this,"_update_graph_connections");
+
+	undo_redo->commit_action();
+
+}
+
+void VisualScriptEditor::_graph_disconnected(const String& p_from,int p_from_slot,const String& p_to,int p_to_slot){
+
+	Ref<VisualScriptNode> from_node = script->get_node(edited_func,p_from.to_int());
+	ERR_FAIL_COND(!from_node.is_valid());
+
+	bool from_seq;
+	int from_port;
+
+	if (!_get_out_slot(from_node,p_from_slot,from_port,from_seq))
+		return; //can't  connect this, it' s invalid
+
+	Ref<VisualScriptNode> to_node = script->get_node(edited_func,p_to.to_int());
+	ERR_FAIL_COND(!to_node.is_valid());
+
+	bool to_seq;
+	int to_port;
+
+	if (!_get_in_slot(to_node,p_to_slot,to_port,to_seq))
+		return; //can't  connect this, it' s invalid
+
+
+	ERR_FAIL_COND(from_seq!=to_seq);
+
+
+	undo_redo->create_action("Connect Nodes");
+
+	if (from_seq) {
+		undo_redo->add_do_method(script.ptr(),"sequence_disconnect",edited_func,p_from.to_int(),from_port,p_to.to_int());
+		undo_redo->add_undo_method(script.ptr(),"sequence_connect",edited_func,p_from.to_int(),from_port,p_to.to_int());
+	} else {
+		undo_redo->add_do_method(script.ptr(),"data_disconnect",edited_func,p_from.to_int(),from_port,p_to.to_int(),to_port);
+		undo_redo->add_undo_method(script.ptr(),"data_connect",edited_func,p_from.to_int(),from_port,p_to.to_int(),to_port);
+	}
+
+	undo_redo->add_do_method(this,"_update_graph_connections");
+	undo_redo->add_undo_method(this,"_update_graph_connections");
+
+	undo_redo->commit_action();
+}
+
+
+void VisualScriptEditor::_bind_methods() {
+
+	ObjectTypeDB::bind_method("_member_button",&VisualScriptEditor::_member_button);
+	ObjectTypeDB::bind_method("_member_edited",&VisualScriptEditor::_member_edited);
+	ObjectTypeDB::bind_method("_member_selected",&VisualScriptEditor::_member_selected);
+	ObjectTypeDB::bind_method("_update_members",&VisualScriptEditor::_update_members);
+	ObjectTypeDB::bind_method("_change_base_type",&VisualScriptEditor::_change_base_type);
+	ObjectTypeDB::bind_method("_change_base_type_callback",&VisualScriptEditor::_change_base_type_callback);
+	ObjectTypeDB::bind_method("_override_pressed",&VisualScriptEditor::_override_pressed);
+	ObjectTypeDB::bind_method("_node_selected",&VisualScriptEditor::_node_selected);
+	ObjectTypeDB::bind_method("_node_moved",&VisualScriptEditor::_node_moved);
+	ObjectTypeDB::bind_method("_move_node",&VisualScriptEditor::_move_node);
+	ObjectTypeDB::bind_method("_begin_node_move",&VisualScriptEditor::_begin_node_move);
+	ObjectTypeDB::bind_method("_end_node_move",&VisualScriptEditor::_end_node_move);
+	ObjectTypeDB::bind_method("_remove_node",&VisualScriptEditor::_remove_node);
+	ObjectTypeDB::bind_method("_update_graph",&VisualScriptEditor::_update_graph,DEFVAL(-1));
+	ObjectTypeDB::bind_method("_node_ports_changed",&VisualScriptEditor::_node_ports_changed);
+	ObjectTypeDB::bind_method("_available_node_doubleclicked",&VisualScriptEditor::_available_node_doubleclicked);
+
+	ObjectTypeDB::bind_method("get_drag_data_fw",&VisualScriptEditor::get_drag_data_fw);
+	ObjectTypeDB::bind_method("can_drop_data_fw",&VisualScriptEditor::can_drop_data_fw);
+	ObjectTypeDB::bind_method("drop_data_fw",&VisualScriptEditor::drop_data_fw);
+
+	ObjectTypeDB::bind_method("_input",&VisualScriptEditor::_input);
+	ObjectTypeDB::bind_method("_on_nodes_delete",&VisualScriptEditor::_on_nodes_delete);
+	ObjectTypeDB::bind_method("_on_nodes_duplicate",&VisualScriptEditor::_on_nodes_duplicate);
+
+
+	ObjectTypeDB::bind_method("_graph_connected",&VisualScriptEditor::_graph_connected);
+	ObjectTypeDB::bind_method("_graph_disconnected",&VisualScriptEditor::_graph_disconnected);
+	ObjectTypeDB::bind_method("_update_graph_connections",&VisualScriptEditor::_update_graph_connections);
+
+
+}
+
+
+
+VisualScriptEditor::VisualScriptEditor() {
+
+	main_hsplit = memnew( HSplitContainer );
+	add_child(main_hsplit);
+	main_hsplit->set_area_as_parent_rect();
+
+	left_vsplit = memnew( VSplitContainer );
+	main_hsplit->add_child(left_vsplit);
+
+	VBoxContainer *left_vb = memnew( VBoxContainer );
+	left_vsplit->add_child(left_vb);
+	left_vb->set_v_size_flags(SIZE_EXPAND_FILL);
+	left_vb->set_custom_minimum_size(Size2(180,1)*EDSCALE);
+
+	base_type_select = memnew( Button );	
+	left_vb->add_margin_child(TTR("Base Type:"),base_type_select);
+	base_type_select->connect("pressed",this,"_change_base_type");
+
+	members = memnew( Tree );
+	left_vb->add_margin_child(TTR("Members:"),members,true);
+	members->set_hide_root(true);
+	members->connect("button_pressed",this,"_member_button");
+	members->connect("item_edited",this,"_member_edited");
+	members->connect("cell_selected",this,"_member_selected");
+	members->set_single_select_cell_editing_only_when_already_selected(true);
+	members->set_hide_folding(true);
+	members->set_drag_forwarding(this);
+
+
+	VBoxContainer *left_vb2 = memnew( VBoxContainer );
+	left_vsplit->add_child(left_vb2);
+	left_vb2->set_v_size_flags(SIZE_EXPAND_FILL);
+
+	nodes = memnew( Tree );
+	left_vb2->add_margin_child(TTR("Available Nodes:"),nodes,true);
+	nodes->set_hide_root(true);
+	nodes->connect("item_activated",this,"_available_node_doubleclicked");
+	nodes->set_drag_forwarding(this);
+
+	graph = memnew( GraphEdit );
+	main_hsplit->add_child(graph);
+	graph->set_h_size_flags(SIZE_EXPAND_FILL);
+	graph->connect("node_selected",this,"_node_selected");
+	graph->connect("_begin_node_move",this,"_begin_node_move");
+	graph->connect("_end_node_move",this,"_end_node_move");
+	graph->connect("delete_nodes_request",this,"_on_nodes_delete");
+	graph->connect("duplicate_nodes_request",this,"_on_nodes_duplicate");
+	graph->set_drag_forwarding(this);
+
+
+
+	//allowed casts (connections)
+	for(int i=0;i<Variant::VARIANT_MAX;i++) {
+		graph->add_valid_connection_type(Variant::NIL,i);
+		graph->add_valid_connection_type(i,Variant::NIL);
+		for(int j=0;j<Variant::VARIANT_MAX;j++) {
+			if (Variant::can_convert(Variant::Type(i),Variant::Type(j))) {
+				graph->add_valid_connection_type(i,j);
+			}
+		}
+
+		graph->add_valid_right_disconnect_type(i);
+	}
+
+	graph->add_valid_left_disconnect_type(TYPE_SEQUENCE);
+
+	graph->connect("connection_request",this,"_graph_connected");
+	graph->connect("disconnection_request",this,"_graph_disconnected");
+
+	edit_signal_dialog = memnew( AcceptDialog );
+	edit_signal_dialog->get_ok()->set_text(TTR("Close"));
+	add_child(edit_signal_dialog);
+	edit_signal_dialog->set_title(TTR("Edit Signal Arguments:"));
+
+	signal_editor = memnew( VisualScriptEditorSignalEdit );
+	edit_signal_edit = memnew( PropertyEditor );
+	edit_signal_edit->hide_top_label();
+	edit_signal_dialog->add_child(edit_signal_edit);
+	edit_signal_dialog->set_child_rect(edit_signal_edit);
+	edit_signal_edit->edit(signal_editor);
+
+	edit_variable_dialog = memnew( AcceptDialog );
+	edit_variable_dialog->get_ok()->set_text(TTR("Close"));
+	add_child(edit_variable_dialog);
+	edit_variable_dialog->set_title(TTR("Edit Variable:"));
+
+	variable_editor = memnew( VisualScriptEditorVariableEdit );
+	edit_variable_edit = memnew( PropertyEditor );
+	edit_variable_edit->hide_top_label();
+	edit_variable_dialog->add_child(edit_variable_edit);
+	edit_variable_dialog->set_child_rect(edit_variable_edit);
+	edit_variable_edit->edit(variable_editor);
+
+	select_base_type=memnew(CreateDialog);
+	select_base_type->set_base_type("Object"); //anything goes
+	select_base_type->connect("create",this,"_change_base_type_callback");
+	select_base_type->get_ok()->set_text(TTR("Change"));
+	add_child(select_base_type);
+
+	undo_redo = EditorNode::get_singleton()->get_undo_redo();
+
+	new_function_menu = memnew( PopupMenu );
+	new_function_menu->connect("item_pressed",this,"_override_pressed");
+	add_child(new_function_menu);
+	updating_members=false;
+
+	set_process_input(true); //for revert on drag
+	set_process_unhandled_input(true); //for revert on drag
+}
+
+VisualScriptEditor::~VisualScriptEditor() {
+
+	undo_redo->clear_history(); //avoid crashes
+	memdelete(signal_editor);
+	memdelete(variable_editor);
+}
+
+static ScriptEditorBase * create_editor(const Ref<Script>& p_script) {
+
+	if (p_script->cast_to<VisualScript>()) {
+		return memnew( VisualScriptEditor );
+	}
+
+	return NULL;
+}
+
+
+void VisualScriptEditor::register_editor() {
+
+	ScriptEditor::register_create_script_editor_function(create_editor);
+}
+

+ 147 - 0
modules/visual_script/visual_script_editor.h

@@ -0,0 +1,147 @@
+#ifndef VisualSCRIPT_EDITOR_H
+#define VisualSCRIPT_EDITOR_H
+
+#include "tools/editor/plugins/script_editor_plugin.h"
+#include "visual_script.h"
+#include "tools/editor/property_editor.h"
+#include "scene/gui/graph_edit.h"
+#include "tools/editor/create_dialog.h"
+
+class VisualScriptEditorSignalEdit;
+class VisualScriptEditorVariableEdit;
+
+
+
+class VisualScriptEditor : public ScriptEditorBase {
+	OBJ_TYPE(VisualScriptEditor,ScriptEditorBase)
+
+	enum {
+		TYPE_SEQUENCE=1000,
+		INDEX_BASE_SEQUENCE=1024
+
+
+	};
+
+	Ref<VisualScript> script;
+
+	Button *base_type_select;
+
+	HSplitContainer *main_hsplit;
+	VSplitContainer *left_vsplit;
+
+	GraphEdit *graph;
+
+	VisualScriptEditorSignalEdit *signal_editor;
+
+	AcceptDialog *edit_signal_dialog;
+	PropertyEditor *edit_signal_edit;
+
+
+	VisualScriptEditorVariableEdit *variable_editor;
+
+	AcceptDialog *edit_variable_dialog;
+	PropertyEditor *edit_variable_edit;
+
+	UndoRedo *undo_redo;
+
+	Tree *members;
+	Tree *nodes;
+
+	CreateDialog *select_base_type;
+
+	struct VirtualInMenu {
+		String name;
+		Variant::Type ret;
+		bool ret_variant;
+		Vector< Pair<Variant::Type,String> > args;
+	};
+
+	Map<int,VirtualInMenu> virtuals_in_menu;
+
+	PopupMenu *new_function_menu;
+
+
+	StringName edited_func;
+
+	void _update_graph_connections();
+	void _update_graph(int p_only_id=-1);
+
+	bool updating_members;
+
+	void _update_members();
+
+	StringName selected;
+
+	String _validate_name(const String& p_name) const;
+
+
+	void _node_selected(Node* p_node);
+
+	void _change_base_type_callback();
+	void _change_base_type();
+	void _member_selected();
+	void _member_edited();
+	void _override_pressed(int p_id);
+
+	void _begin_node_move();
+	void _end_node_move();
+	void _move_node(String func,int p_id,const Vector2& p_to);
+
+	void _node_moved(Vector2 p_from,Vector2 p_to, int p_id);
+	void _remove_node(int p_id);
+	void _graph_connected(const String& p_from,int p_from_slot,const String& p_to,int p_to_slot);
+	void _graph_disconnected(const String& p_from,int p_from_slot,const String& p_to,int p_to_slot);
+	void _node_ports_changed(const String& p_func,int p_id);
+	void _available_node_doubleclicked();
+
+	void _update_available_nodes();
+
+	void _member_button(Object *p_item, int p_column, int p_button);
+
+
+	String revert_on_drag;
+
+	void _input(const InputEvent& p_event);
+	void _on_nodes_delete();
+	void _on_nodes_duplicate();
+
+	Variant get_drag_data_fw(const Point2& p_point,Control* p_from);
+	bool can_drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from) const;
+	void drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from);
+
+
+protected:
+
+	static void _bind_methods();
+public:
+
+	virtual void apply_code();
+	virtual Ref<Script> get_edited_script() const;
+	virtual Vector<String> get_functions();
+	virtual void set_edited_script(const Ref<Script>& p_script);
+	virtual void reload_text();
+	virtual String get_name();
+	virtual Ref<Texture> get_icon();
+	virtual bool is_unsaved();
+	virtual Variant get_edit_state();
+	virtual void set_edit_state(const Variant& p_state);
+	virtual void goto_line(int p_line);
+	virtual void trim_trailing_whitespace();
+	virtual void ensure_focus();
+	virtual void tag_saved_version();
+	virtual void reload(bool p_soft);
+	virtual void get_breakpoints(List<int> *p_breakpoints);
+	virtual bool goto_method(const String& p_method);
+	virtual void add_callback(const String& p_function,StringArray p_args);
+	virtual void update_settings();
+
+	virtual void set_tooltip_request_func(String p_method,Object* p_obj);
+	virtual Control *get_edit_menu();
+
+	static void register_editor();
+
+	VisualScriptEditor();
+	~VisualScriptEditor();
+};
+
+#endif // VisualSCRIPT_EDITOR_H

+ 418 - 0
modules/visual_script/visual_script_flow_control.cpp

@@ -0,0 +1,418 @@
+#include "visual_script_flow_control.h"
+
+//////////////////////////////////////////
+////////////////RETURN////////////////////
+//////////////////////////////////////////
+
+int VisualScriptReturn::get_output_sequence_port_count() const {
+
+	return 0;
+}
+
+bool VisualScriptReturn::has_input_sequence_port() const{
+
+	return true;
+}
+
+int VisualScriptReturn::get_input_value_port_count() const{
+
+	return with_value?1:0;
+}
+int VisualScriptReturn::get_output_value_port_count() const{
+
+	return 0;
+}
+
+String VisualScriptReturn::get_output_sequence_port_text(int p_port) const {
+
+	return String();
+}
+
+PropertyInfo VisualScriptReturn::get_input_value_port_info(int p_idx) const{
+
+	PropertyInfo pinfo;
+	pinfo.name="result";
+	pinfo.type=type;
+	return pinfo;
+}
+PropertyInfo VisualScriptReturn::get_output_value_port_info(int p_idx) const{
+	return PropertyInfo();
+}
+
+String VisualScriptReturn::get_caption() const {
+
+	return "Return";
+}
+
+String VisualScriptReturn::get_text() const {
+
+	return get_name();
+}
+
+void VisualScriptReturn::set_return_type(Variant::Type p_type) {
+
+	if (type==p_type)
+		return;
+	type=p_type;
+	emit_signal("ports_changed");
+
+}
+
+Variant::Type VisualScriptReturn::get_return_type() const{
+
+	return type;
+}
+
+void VisualScriptReturn::set_enable_return_value(bool p_enable) {
+	if (with_value==p_enable)
+		return;
+
+	with_value=p_enable;
+	emit_signal("ports_changed");
+}
+
+bool VisualScriptReturn::is_return_value_enabled() const {
+
+	return with_value;
+}
+
+void VisualScriptReturn::_bind_methods() {
+
+	ObjectTypeDB::bind_method(_MD("set_return_type","type"),&VisualScriptReturn::set_return_type);
+	ObjectTypeDB::bind_method(_MD("get_return_type"),&VisualScriptReturn::get_return_type);
+	ObjectTypeDB::bind_method(_MD("set_enable_return_value","enable"),&VisualScriptReturn::set_enable_return_value);
+	ObjectTypeDB::bind_method(_MD("is_return_value_enabled"),&VisualScriptReturn::is_return_value_enabled);
+
+	String argt="Variant";
+	for(int i=1;i<Variant::VARIANT_MAX;i++) {
+		argt+=","+Variant::get_type_name(Variant::Type(i));
+	}
+
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL,"return_value/enabled"),_SCS("set_enable_return_value"),_SCS("is_return_value_enabled"));
+	ADD_PROPERTY(PropertyInfo(Variant::INT,"return_value/type",PROPERTY_HINT_ENUM,argt),_SCS("set_return_type"),_SCS("get_return_type"));
+
+}
+
+VisualScriptNodeInstance* VisualScriptReturn::instance(VScriptInstance* p_instance) {
+
+	return NULL;
+}
+
+VisualScriptReturn::VisualScriptReturn() {
+
+	with_value=false;
+	type=Variant::NIL;
+}
+
+template<bool with_value>
+static Ref<VisualScriptNode> create_return_node(const String& p_name) {
+
+	Ref<VisualScriptReturn> node;
+	node.instance();
+	node->set_enable_return_value(with_value);
+	return node;
+}
+
+
+
+//////////////////////////////////////////
+////////////////CONDITION/////////////////
+//////////////////////////////////////////
+
+int VisualScriptCondition::get_output_sequence_port_count() const {
+
+	return 2;
+}
+
+bool VisualScriptCondition::has_input_sequence_port() const{
+
+	return true;
+}
+
+int VisualScriptCondition::get_input_value_port_count() const{
+
+	return 1;
+}
+int VisualScriptCondition::get_output_value_port_count() const{
+
+	return 0;
+}
+
+String VisualScriptCondition::get_output_sequence_port_text(int p_port) const {
+
+	if (p_port==0)
+		return "true";
+	else
+		return "false";
+}
+
+PropertyInfo VisualScriptCondition::get_input_value_port_info(int p_idx) const{
+
+	PropertyInfo pinfo;
+	pinfo.name="cond";
+	pinfo.type=Variant::BOOL;
+	return pinfo;
+}
+PropertyInfo VisualScriptCondition::get_output_value_port_info(int p_idx) const{
+	return PropertyInfo();
+}
+
+String VisualScriptCondition::get_caption() const {
+
+	return "Condition";
+}
+
+String VisualScriptCondition::get_text() const {
+
+	return "if (cond) is:  ";
+}
+
+
+void VisualScriptCondition::_bind_methods() {
+
+
+
+}
+
+VisualScriptNodeInstance* VisualScriptCondition::instance(VScriptInstance* p_instance) {
+
+	return NULL;
+}
+
+VisualScriptCondition::VisualScriptCondition() {
+
+}
+
+
+
+//////////////////////////////////////////
+////////////////WHILE/////////////////
+//////////////////////////////////////////
+
+int VisualScriptWhile::get_output_sequence_port_count() const {
+
+	return 2;
+}
+
+bool VisualScriptWhile::has_input_sequence_port() const{
+
+	return true;
+}
+
+int VisualScriptWhile::get_input_value_port_count() const{
+
+	return 1;
+}
+int VisualScriptWhile::get_output_value_port_count() const{
+
+	return 0;
+}
+
+String VisualScriptWhile::get_output_sequence_port_text(int p_port) const {
+
+	if (p_port==0)
+		return "repeat";
+	else
+		return "exit";
+}
+
+PropertyInfo VisualScriptWhile::get_input_value_port_info(int p_idx) const{
+
+	PropertyInfo pinfo;
+	pinfo.name="cond";
+	pinfo.type=Variant::BOOL;
+	return pinfo;
+}
+PropertyInfo VisualScriptWhile::get_output_value_port_info(int p_idx) const{
+	return PropertyInfo();
+}
+
+String VisualScriptWhile::get_caption() const {
+
+	return "While";
+}
+
+String VisualScriptWhile::get_text() const {
+
+	return "while (cond): ";
+}
+
+
+void VisualScriptWhile::_bind_methods() {
+
+
+
+}
+
+VisualScriptNodeInstance* VisualScriptWhile::instance(VScriptInstance* p_instance) {
+
+	return NULL;
+}
+
+VisualScriptWhile::VisualScriptWhile() {
+
+}
+
+
+
+//////////////////////////////////////////
+////////////////ITERATOR/////////////////
+//////////////////////////////////////////
+
+int VisualScriptIterator::get_output_sequence_port_count() const {
+
+	return 2;
+}
+
+bool VisualScriptIterator::has_input_sequence_port() const{
+
+	return true;
+}
+
+int VisualScriptIterator::get_input_value_port_count() const{
+
+	return 1;
+}
+int VisualScriptIterator::get_output_value_port_count() const{
+
+	return 1;
+}
+
+String VisualScriptIterator::get_output_sequence_port_text(int p_port) const {
+
+	if (p_port==0)
+		return "each";
+	else
+		return "exit";
+}
+
+PropertyInfo VisualScriptIterator::get_input_value_port_info(int p_idx) const{
+
+	PropertyInfo pinfo;
+	pinfo.name="input";
+	pinfo.type=Variant::NIL;
+	return pinfo;
+}
+PropertyInfo VisualScriptIterator::get_output_value_port_info(int p_idx) const{
+	PropertyInfo pinfo;
+	pinfo.name="elem";
+	pinfo.type=Variant::NIL;
+	return pinfo;
+}
+String VisualScriptIterator::get_caption() const {
+
+	return "Iterator";
+}
+
+String VisualScriptIterator::get_text() const {
+
+	return "for (elem) in (input): ";
+}
+
+
+void VisualScriptIterator::_bind_methods() {
+
+
+
+}
+
+VisualScriptNodeInstance* VisualScriptIterator::instance(VScriptInstance* p_instance) {
+
+	return NULL;
+}
+
+VisualScriptIterator::VisualScriptIterator() {
+
+}
+
+
+
+//////////////////////////////////////////
+////////////////SEQUENCE/////////////////
+//////////////////////////////////////////
+
+int VisualScriptSequence::get_output_sequence_port_count() const {
+
+	return steps;
+}
+
+bool VisualScriptSequence::has_input_sequence_port() const{
+
+	return true;
+}
+
+int VisualScriptSequence::get_input_value_port_count() const{
+
+	return 0;
+}
+int VisualScriptSequence::get_output_value_port_count() const{
+
+	return 1;
+}
+
+String VisualScriptSequence::get_output_sequence_port_text(int p_port) const {
+
+	return itos(p_port+1);
+}
+
+PropertyInfo VisualScriptSequence::get_input_value_port_info(int p_idx) const{
+	return PropertyInfo();
+}
+PropertyInfo VisualScriptSequence::get_output_value_port_info(int p_idx) const{
+	return PropertyInfo(Variant::INT,"current");
+}
+String VisualScriptSequence::get_caption() const {
+
+	return "Sequence";
+}
+
+String VisualScriptSequence::get_text() const {
+
+	return "in order: ";
+}
+
+void VisualScriptSequence::set_steps(int p_steps) {
+
+	ERR_FAIL_COND(p_steps<1);
+	if (steps==p_steps)
+		return;
+
+	steps=p_steps;
+	emit_signal("ports_changed");
+
+}
+
+int VisualScriptSequence::get_steps() const {
+
+	return steps;
+}
+
+void VisualScriptSequence::_bind_methods() {
+
+	ObjectTypeDB::bind_method(_MD("set_steps","steps"),&VisualScriptSequence::set_steps);
+	ObjectTypeDB::bind_method(_MD("get_steps"),&VisualScriptSequence::get_steps);
+
+	ADD_PROPERTY(PropertyInfo(Variant::INT,"steps",PROPERTY_HINT_RANGE,"1,64,1"),_SCS("set_steps"),_SCS("get_steps"));
+
+}
+
+VisualScriptNodeInstance* VisualScriptSequence::instance(VScriptInstance* p_instance) {
+
+	return NULL;
+}
+
+VisualScriptSequence::VisualScriptSequence() {
+
+	steps=1;
+}
+
+void register_visual_script_flow_control_nodes() {
+
+	VisualScriptLanguage::singleton->add_register_func("flow_control/return",create_return_node<false>);
+	VisualScriptLanguage::singleton->add_register_func("flow_control/return_with_value",create_return_node<true>);
+	VisualScriptLanguage::singleton->add_register_func("flow_control/condition",create_node_generic<VisualScriptCondition>);
+	VisualScriptLanguage::singleton->add_register_func("flow_control/while",create_node_generic<VisualScriptWhile>);
+	VisualScriptLanguage::singleton->add_register_func("flow_control/iterator",create_node_generic<VisualScriptIterator>);
+	VisualScriptLanguage::singleton->add_register_func("flow_control/sequence",create_node_generic<VisualScriptSequence>);
+
+}

+ 196 - 0
modules/visual_script/visual_script_flow_control.h

@@ -0,0 +1,196 @@
+#ifndef VISUAL_SCRIPT_FLOW_CONTROL_H
+#define VISUAL_SCRIPT_FLOW_CONTROL_H
+
+#include "visual_script.h"
+
+class VisualScriptReturn : public VisualScriptNode {
+
+	OBJ_TYPE(VisualScriptReturn,VisualScriptNode)
+
+
+	Variant::Type type;
+	bool with_value;
+protected:
+
+	static void _bind_methods();
+public:
+
+	virtual int get_output_sequence_port_count() const;
+	virtual bool has_input_sequence_port() const;
+
+
+	virtual String get_output_sequence_port_text(int p_port) const;
+
+
+	virtual int get_input_value_port_count() const;
+	virtual int get_output_value_port_count() const;
+
+
+	virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+	virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+	virtual String get_caption() const;
+	virtual String get_text() const;
+
+	void set_return_type(Variant::Type);
+	Variant::Type get_return_type() const;
+
+	void set_enable_return_value(bool p_enable);
+	bool is_return_value_enabled() const;
+
+
+	virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance);
+
+	VisualScriptReturn();
+};
+
+
+class VisualScriptCondition : public VisualScriptNode {
+
+	OBJ_TYPE(VisualScriptCondition,VisualScriptNode)
+
+
+
+protected:
+
+	static void _bind_methods();
+public:
+
+	virtual int get_output_sequence_port_count() const;
+	virtual bool has_input_sequence_port() const;
+
+
+	virtual String get_output_sequence_port_text(int p_port) const;
+
+
+	virtual int get_input_value_port_count() const;
+	virtual int get_output_value_port_count() const;
+
+
+	virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+	virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+	virtual String get_caption() const;
+	virtual String get_text() const;
+
+
+	virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance);
+
+	VisualScriptCondition();
+};
+
+
+class VisualScriptWhile : public VisualScriptNode {
+
+	OBJ_TYPE(VisualScriptWhile,VisualScriptNode)
+
+
+
+protected:
+
+	static void _bind_methods();
+public:
+
+	virtual int get_output_sequence_port_count() const;
+	virtual bool has_input_sequence_port() const;
+
+
+	virtual String get_output_sequence_port_text(int p_port) const;
+
+
+	virtual int get_input_value_port_count() const;
+	virtual int get_output_value_port_count() const;
+
+
+	virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+	virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+	virtual String get_caption() const;
+	virtual String get_text() const;
+
+
+	virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance);
+
+	VisualScriptWhile();
+};
+
+
+
+class VisualScriptIterator : public VisualScriptNode {
+
+	OBJ_TYPE(VisualScriptIterator,VisualScriptNode)
+
+
+
+protected:
+
+	static void _bind_methods();
+public:
+
+	virtual int get_output_sequence_port_count() const;
+	virtual bool has_input_sequence_port() const;
+
+
+	virtual String get_output_sequence_port_text(int p_port) const;
+
+
+	virtual int get_input_value_port_count() const;
+	virtual int get_output_value_port_count() const;
+
+
+	virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+	virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+	virtual String get_caption() const;
+	virtual String get_text() const;
+
+
+	virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance);
+
+	VisualScriptIterator();
+};
+
+
+
+class VisualScriptSequence : public VisualScriptNode {
+
+	OBJ_TYPE(VisualScriptSequence,VisualScriptNode)
+
+
+	int steps;
+
+protected:
+
+	static void _bind_methods();
+public:
+
+	virtual int get_output_sequence_port_count() const;
+	virtual bool has_input_sequence_port() const;
+
+
+	virtual String get_output_sequence_port_text(int p_port) const;
+
+
+	virtual int get_input_value_port_count() const;
+	virtual int get_output_value_port_count() const;
+
+
+	virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+	virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+	virtual String get_caption() const;
+	virtual String get_text() const;
+
+	void set_steps(int p_steps);
+	int get_steps() const;
+
+	virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance);
+
+	VisualScriptSequence();
+};
+
+void register_visual_script_flow_control_nodes();
+
+
+
+#endif // VISUAL_SCRIPT_FLOW_CONTROL_H

+ 1584 - 0
modules/visual_script/visual_script_func_nodes.cpp

@@ -0,0 +1,1584 @@
+#include "visual_script_func_nodes.h"
+#include "scene/main/scene_main_loop.h"
+#include "os/os.h"
+#include "scene/main/node.h"
+#include "visual_script_nodes.h"
+
+//////////////////////////////////////////
+////////////////CALL//////////////////////
+//////////////////////////////////////////
+
+int VisualScriptFunctionCall::get_output_sequence_port_count() const {
+
+	return 1;
+}
+
+bool VisualScriptFunctionCall::has_input_sequence_port() const{
+
+	return true;
+}
+#ifdef TOOLS_ENABLED
+
+static Node* _find_script_node(Node* p_edited_scene,Node* p_current_node,const Ref<Script> &script) {
+
+	if (p_edited_scene!=p_current_node && p_current_node->get_owner()!=p_edited_scene)
+		return NULL;
+
+	Ref<Script> scr = p_current_node->get_script();
+
+	if (scr.is_valid() && scr==script)
+		return p_current_node;
+
+	for(int i=0;i<p_current_node->get_child_count();i++) {
+		Node *n = _find_script_node(p_edited_scene,p_current_node->get_child(i),script);
+		if (n)
+			return n;
+	}
+
+	return NULL;
+}
+
+#endif
+Node *VisualScriptFunctionCall::_get_base_node() const {
+
+#ifdef TOOLS_ENABLED
+	Ref<Script> script = get_visual_script();
+	if (!script.is_valid())
+		return NULL;
+
+	MainLoop * main_loop = OS::get_singleton()->get_main_loop();
+	if (!main_loop)
+		return NULL;
+
+	SceneTree *scene_tree = main_loop->cast_to<SceneTree>();
+
+	if (!scene_tree)
+		return NULL;
+
+	Node *edited_scene = scene_tree->get_edited_scene_root();
+
+	if (!edited_scene)
+		return NULL;
+
+	Node* script_node = _find_script_node(edited_scene,edited_scene,script);
+
+	if (!script_node)
+		return NULL;
+
+	if (!script_node->has_node(base_path))
+		return NULL;
+
+	Node *path_to = script_node->get_node(base_path);
+
+	return path_to;
+#else
+
+	return NULL;
+#endif
+}
+
+StringName VisualScriptFunctionCall::_get_base_type() const {
+
+	if (call_mode==CALL_MODE_SELF && get_visual_script().is_valid())
+		return get_visual_script()->get_instance_base_type();
+	else if (call_mode==CALL_MODE_NODE_PATH && get_visual_script().is_valid()) {
+		Node *path = _get_base_node();
+		if (path)
+			return path->get_type();
+
+	}
+
+	return base_type;
+}
+
+int VisualScriptFunctionCall::get_input_value_port_count() const{
+
+	MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function);
+	if (!mb)
+		return 0;
+
+	return mb->get_argument_count() + (call_mode==CALL_MODE_INSTANCE?1:0) - use_default_args;
+
+}
+int VisualScriptFunctionCall::get_output_value_port_count() const{
+
+	MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function);
+	if (!mb)
+		return 0;
+
+	return mb->has_return() ? 1 : 0;
+}
+
+String VisualScriptFunctionCall::get_output_sequence_port_text(int p_port) const {
+
+	return String();
+}
+
+PropertyInfo VisualScriptFunctionCall::get_input_value_port_info(int p_idx) const{
+
+	if (call_mode==CALL_MODE_INSTANCE) {
+		if (p_idx==0) {
+			PropertyInfo pi;
+			pi.type=Variant::OBJECT;
+			pi.name="instance";
+			return pi;
+		} else {
+			p_idx--;
+		}
+	}
+
+#ifdef DEBUG_METHODS_ENABLED
+
+
+
+	MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function);
+	if (!mb)
+		return PropertyInfo();
+
+	return mb->get_argument_info(p_idx);
+#else
+	return PropertyInfo();
+#endif
+
+}
+
+PropertyInfo VisualScriptFunctionCall::get_output_value_port_info(int p_idx) const{
+
+
+#ifdef DEBUG_METHODS_ENABLED
+
+	MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function);
+	if (!mb)
+		return PropertyInfo();
+
+	PropertyInfo pi = mb->get_argument_info(-1);
+	pi.name="";
+	return pi;
+#else
+	return PropertyInfo();
+#endif
+}
+
+
+String VisualScriptFunctionCall::get_caption() const {
+
+	return "Call";
+}
+
+String VisualScriptFunctionCall::get_text() const {
+
+	if (call_mode==CALL_MODE_SELF)
+		return "  "+String(function)+"()";
+	else
+		return "  "+base_type+"."+String(function)+"()";
+
+}
+
+void VisualScriptFunctionCall::_update_defargs() {
+
+	if (!get_visual_script().is_valid())
+		return; //do not change if not valid yet
+
+	MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function);
+	if (!mb)
+		return;
+
+	use_default_args=mb->get_default_argument_count();
+
+}
+
+void VisualScriptFunctionCall::set_base_type(const StringName& p_type) {
+
+	if (base_type==p_type)
+		return;
+
+	base_type=p_type;
+	_update_defargs();
+	_change_notify();
+	emit_signal("ports_changed");
+}
+
+StringName VisualScriptFunctionCall::get_base_type() const{
+
+	return base_type;
+}
+
+void VisualScriptFunctionCall::set_function(const StringName& p_type){
+
+	if (function==p_type)
+		return;
+
+	function=p_type;
+	_update_defargs();
+	_change_notify();
+	emit_signal("ports_changed");
+}
+StringName VisualScriptFunctionCall::get_function() const {
+
+
+	return function;
+}
+
+void VisualScriptFunctionCall::set_base_path(const NodePath& p_type) {
+
+	if (base_path==p_type)
+		return;
+
+	base_path=p_type;
+	_update_defargs();
+	_change_notify();
+	emit_signal("ports_changed");
+}
+
+NodePath VisualScriptFunctionCall::get_base_path() const {
+
+	return base_path;
+}
+
+
+void VisualScriptFunctionCall::set_call_mode(CallMode p_mode) {
+
+	if (call_mode==p_mode)
+		return;
+
+	call_mode=p_mode;
+	_update_defargs();
+	_change_notify();
+	emit_signal("ports_changed");
+
+}
+VisualScriptFunctionCall::CallMode VisualScriptFunctionCall::get_call_mode() const {
+
+	return call_mode;
+}
+
+void VisualScriptFunctionCall::set_use_default_args(int p_amount) {
+
+	if (use_default_args==p_amount)
+		return;
+
+	use_default_args=p_amount;
+	emit_signal("ports_changed");
+
+
+}
+
+int VisualScriptFunctionCall::get_use_default_args() const{
+
+	return use_default_args;
+}
+void VisualScriptFunctionCall::_validate_property(PropertyInfo& property) const {
+
+	if (property.name=="function/base_type") {
+		if (call_mode!=CALL_MODE_INSTANCE) {
+			property.usage=0;
+		}
+	}
+
+
+	if (property.name=="function/node_path") {
+		if (call_mode!=CALL_MODE_NODE_PATH) {
+			property.usage=0;
+		} else {
+
+			Node *bnode = _get_base_node();
+			if (bnode) {
+				property.hint_string=bnode->get_path(); //convert to loong string
+			} else {
+
+			}
+		}
+	}
+
+	if (property.name=="function/function") {
+		property.hint=PROPERTY_HINT_ENUM;
+
+
+		List<MethodInfo> methods;
+
+		StringName base = _get_base_type();
+		ObjectTypeDB::get_method_list(base,&methods);
+
+
+		List<String> mstring;
+		for (List<MethodInfo>::Element *E=methods.front();E;E=E->next()) {
+			if (E->get().name.begins_with("_"))
+				continue;
+			mstring.push_back(E->get().name.get_slice(":",0));
+		}
+
+		mstring.sort();
+
+		String ml;
+		for (List<String>::Element *E=mstring.front();E;E=E->next()) {
+
+			if (ml!=String())
+				ml+=",";
+			ml+=E->get();
+		}
+
+		property.hint_string=ml;
+	}
+
+	if (property.name=="function/use_default_args") {
+		property.hint=PROPERTY_HINT_RANGE;
+
+		int mc=0;
+
+		MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function);
+		if (mb) {
+
+			mc=mb->get_default_argument_count();
+		}
+
+		property.hint_string="0,"+itos(mc)+",1";
+	}
+}
+
+
+void VisualScriptFunctionCall::_bind_methods() {
+
+	ObjectTypeDB::bind_method(_MD("set_base_type","base_type"),&VisualScriptFunctionCall::set_base_type);
+	ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptFunctionCall::get_base_type);
+
+	ObjectTypeDB::bind_method(_MD("set_function","function"),&VisualScriptFunctionCall::set_function);
+	ObjectTypeDB::bind_method(_MD("get_function"),&VisualScriptFunctionCall::get_function);
+
+	ObjectTypeDB::bind_method(_MD("set_call_mode","mode"),&VisualScriptFunctionCall::set_call_mode);
+	ObjectTypeDB::bind_method(_MD("get_call_mode"),&VisualScriptFunctionCall::get_call_mode);
+
+	ObjectTypeDB::bind_method(_MD("set_base_path","base_path"),&VisualScriptFunctionCall::set_base_path);
+	ObjectTypeDB::bind_method(_MD("get_base_path"),&VisualScriptFunctionCall::get_base_path);
+
+	ObjectTypeDB::bind_method(_MD("set_use_default_args","amount"),&VisualScriptFunctionCall::set_use_default_args);
+	ObjectTypeDB::bind_method(_MD("get_use_default_args"),&VisualScriptFunctionCall::get_use_default_args);
+
+
+	ADD_PROPERTY(PropertyInfo(Variant::INT,"function/call_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance"),_SCS("set_call_mode"),_SCS("get_call_mode"));
+	ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type"));
+	ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"function/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_base_path"),_SCS("get_base_path"));
+	ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/function"),_SCS("set_function"),_SCS("get_function"));
+	ADD_PROPERTY(PropertyInfo(Variant::INT,"function/use_default_args"),_SCS("set_use_default_args"),_SCS("get_use_default_args"));
+
+	BIND_CONSTANT( CALL_MODE_SELF );
+	BIND_CONSTANT( CALL_MODE_NODE_PATH);
+	BIND_CONSTANT( CALL_MODE_INSTANCE);
+}
+
+VisualScriptNodeInstance* VisualScriptFunctionCall::instance(VScriptInstance* p_instance) {
+
+	return NULL;
+}
+
+VisualScriptFunctionCall::VisualScriptFunctionCall() {
+
+	call_mode=CALL_MODE_INSTANCE;
+	use_default_args=0;
+	base_type="Object";
+
+}
+
+template<VisualScriptFunctionCall::CallMode cmode>
+static Ref<VisualScriptNode> create_function_call_node(const String& p_name) {
+
+	Ref<VisualScriptFunctionCall> node;
+	node.instance();
+	node->set_call_mode(cmode);
+	return node;
+}
+
+
+//////////////////////////////////////////
+////////////////SET//////////////////////
+//////////////////////////////////////////
+
+int VisualScriptPropertySet::get_output_sequence_port_count() const {
+
+	return 1;
+}
+
+bool VisualScriptPropertySet::has_input_sequence_port() const{
+
+	return true;
+}
+
+Node *VisualScriptPropertySet::_get_base_node() const {
+
+#ifdef TOOLS_ENABLED
+	Ref<Script> script = get_visual_script();
+	if (!script.is_valid())
+		return NULL;
+
+	MainLoop * main_loop = OS::get_singleton()->get_main_loop();
+	if (!main_loop)
+		return NULL;
+
+	SceneTree *scene_tree = main_loop->cast_to<SceneTree>();
+
+	if (!scene_tree)
+		return NULL;
+
+	Node *edited_scene = scene_tree->get_edited_scene_root();
+
+	if (!edited_scene)
+		return NULL;
+
+	Node* script_node = _find_script_node(edited_scene,edited_scene,script);
+
+	if (!script_node)
+		return NULL;
+
+	if (!script_node->has_node(base_path))
+		return NULL;
+
+	Node *path_to = script_node->get_node(base_path);
+
+	return path_to;
+#else
+
+	return NULL;
+#endif
+}
+
+StringName VisualScriptPropertySet::_get_base_type() const {
+
+	if (call_mode==CALL_MODE_SELF && get_visual_script().is_valid())
+		return get_visual_script()->get_instance_base_type();
+	else if (call_mode==CALL_MODE_NODE_PATH && get_visual_script().is_valid()) {
+		Node *path = _get_base_node();
+		if (path)
+			return path->get_type();
+
+	}
+
+	return base_type;
+}
+
+int VisualScriptPropertySet::get_input_value_port_count() const{
+
+	if (use_builtin_value)
+		return 0;
+	else
+		return 1;
+
+
+}
+int VisualScriptPropertySet::get_output_value_port_count() const{
+
+	return 0;
+}
+
+String VisualScriptPropertySet::get_output_sequence_port_text(int p_port) const {
+
+	return String();
+}
+
+PropertyInfo VisualScriptPropertySet::get_input_value_port_info(int p_idx) const{
+
+	if (call_mode==CALL_MODE_INSTANCE) {
+		if (p_idx==0) {
+			PropertyInfo pi;
+			pi.type=Variant::OBJECT;
+			pi.name="instance";
+			return pi;
+		} else {
+			p_idx--;
+		}
+	}
+
+#ifdef DEBUG_METHODS_ENABLED
+
+	//not very efficient but..
+
+
+	List<PropertyInfo> pinfo;
+
+	if (call_mode==CALL_MODE_NODE_PATH) {
+
+		Node *n = _get_base_node();
+		if (n) {
+			n->get_property_list(&pinfo);
+		} else {
+			ObjectTypeDB::get_property_list(_get_base_type(),&pinfo);
+		}
+	} else {
+		ObjectTypeDB::get_property_list(_get_base_type(),&pinfo);
+	}
+
+	for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+
+		if (E->get().name==property) {
+
+			PropertyInfo info=E->get();
+			info.name="value";
+			return info;
+		}
+	}
+
+
+#endif
+
+	return PropertyInfo(Variant::NIL,"value");
+
+}
+
+PropertyInfo VisualScriptPropertySet::get_output_value_port_info(int p_idx) const{
+
+	return PropertyInfo();
+
+}
+
+
+String VisualScriptPropertySet::get_caption() const {
+
+	return "Set";
+}
+
+String VisualScriptPropertySet::get_text() const {
+
+	return property;
+
+}
+
+void VisualScriptPropertySet::set_base_type(const StringName& p_type) {
+
+	if (base_type==p_type)
+		return;
+
+	base_type=p_type;
+	_change_notify();
+	emit_signal("ports_changed");
+}
+
+StringName VisualScriptPropertySet::get_base_type() const{
+
+	return base_type;
+}
+
+void VisualScriptPropertySet::set_property(const StringName& p_type){
+
+	if (property==p_type)
+		return;
+
+	property=p_type;
+	_change_notify();
+	emit_signal("ports_changed");
+}
+StringName VisualScriptPropertySet::get_property() const {
+
+
+	return property;
+}
+
+void VisualScriptPropertySet::set_base_path(const NodePath& p_type) {
+
+	if (base_path==p_type)
+		return;
+
+	base_path=p_type;
+	_change_notify();
+	emit_signal("ports_changed");
+}
+
+NodePath VisualScriptPropertySet::get_base_path() const {
+
+	return base_path;
+}
+
+
+void VisualScriptPropertySet::set_call_mode(CallMode p_mode) {
+
+	if (call_mode==p_mode)
+		return;
+
+	call_mode=p_mode;
+	_change_notify();
+	emit_signal("ports_changed");
+
+}
+VisualScriptPropertySet::CallMode VisualScriptPropertySet::get_call_mode() const {
+
+	return call_mode;
+}
+
+
+void VisualScriptPropertySet::set_use_builtin_value(bool p_use) {
+
+	if (use_builtin_value==p_use)
+		return;
+
+	use_builtin_value=p_use;
+	_change_notify();
+	emit_signal("ports_changed");
+
+}
+
+bool VisualScriptPropertySet::is_using_builtin_value() const{
+
+	return use_builtin_value;
+}
+
+void VisualScriptPropertySet::set_builtin_value(const Variant& p_value){
+
+	if (builtin_value==p_value)
+		return;
+
+	builtin_value=p_value;
+
+}
+Variant VisualScriptPropertySet::get_builtin_value() const{
+
+	return builtin_value;
+}
+void VisualScriptPropertySet::_validate_property(PropertyInfo& property) const {
+
+	if (property.name=="property/base_type") {
+		if (call_mode!=CALL_MODE_INSTANCE) {
+			property.usage=0;
+		}
+	}
+
+
+	if (property.name=="property/node_path") {
+		if (call_mode!=CALL_MODE_NODE_PATH) {
+			property.usage=0;
+		} else {
+
+			Node *bnode = _get_base_node();
+			if (bnode) {
+				property.hint_string=bnode->get_path(); //convert to loong string
+			} else {
+
+			}
+		}
+	}
+
+	if (property.name=="property/property") {
+		property.hint=PROPERTY_HINT_ENUM;
+
+
+		List<PropertyInfo> pinfo;
+
+		if (call_mode==CALL_MODE_NODE_PATH) {
+
+			Node *n = _get_base_node();
+			if (n) {
+				n->get_property_list(&pinfo);
+			} else {
+				ObjectTypeDB::get_property_list(_get_base_type(),&pinfo);
+			}
+		} else {
+			ObjectTypeDB::get_property_list(_get_base_type(),&pinfo);
+		}
+
+		List<String> mstring;
+
+		for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+
+			if (E->get().usage&PROPERTY_USAGE_EDITOR)
+				mstring.push_back(E->get().name);
+		}
+
+		String ml;
+		for (List<String>::Element *E=mstring.front();E;E=E->next()) {
+
+			if (ml!=String())
+				ml+=",";
+			ml+=E->get();
+		}
+
+		property.hint_string=ml;
+	}
+
+	if (property.name=="value/builtin") {
+
+		if (!use_builtin_value) {
+			property.usage=0;
+		} else {
+			List<PropertyInfo> pinfo;
+
+
+			if (call_mode==CALL_MODE_NODE_PATH) {
+
+				Node *n = _get_base_node();
+				if (n) {
+					n->get_property_list(&pinfo);
+				} else {
+					ObjectTypeDB::get_property_list(_get_base_type(),&pinfo);
+				}
+			} else {
+				ObjectTypeDB::get_property_list(_get_base_type(),&pinfo);
+			}
+
+			for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+
+				if (E->get().name==this->property) {
+
+					property.hint=E->get().hint;
+					property.type=E->get().type;
+					property.hint_string=E->get().hint_string;
+				}
+			}
+		}
+
+	}
+}
+
+void VisualScriptPropertySet::_bind_methods() {
+
+	ObjectTypeDB::bind_method(_MD("set_base_type","base_type"),&VisualScriptPropertySet::set_base_type);
+	ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptPropertySet::get_base_type);
+
+	ObjectTypeDB::bind_method(_MD("set_property","property"),&VisualScriptPropertySet::set_property);
+	ObjectTypeDB::bind_method(_MD("get_property"),&VisualScriptPropertySet::get_property);
+
+	ObjectTypeDB::bind_method(_MD("set_call_mode","mode"),&VisualScriptPropertySet::set_call_mode);
+	ObjectTypeDB::bind_method(_MD("get_call_mode"),&VisualScriptPropertySet::get_call_mode);
+
+	ObjectTypeDB::bind_method(_MD("set_base_path","base_path"),&VisualScriptPropertySet::set_base_path);
+	ObjectTypeDB::bind_method(_MD("get_base_path"),&VisualScriptPropertySet::get_base_path);
+
+	ObjectTypeDB::bind_method(_MD("set_builtin_value","value"),&VisualScriptPropertySet::set_builtin_value);
+	ObjectTypeDB::bind_method(_MD("get_builtin_value"),&VisualScriptPropertySet::get_builtin_value);
+
+	ObjectTypeDB::bind_method(_MD("set_use_builtin_value","enable"),&VisualScriptPropertySet::set_use_builtin_value);
+	ObjectTypeDB::bind_method(_MD("is_using_builtin_value"),&VisualScriptPropertySet::is_using_builtin_value);
+
+	ADD_PROPERTY(PropertyInfo(Variant::INT,"property/set_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance"),_SCS("set_call_mode"),_SCS("get_call_mode"));
+	ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type"));
+	ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"property/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_base_path"),_SCS("get_base_path"));
+	ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/property"),_SCS("set_property"),_SCS("get_property"));
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL,"value/use_builtin"),_SCS("set_use_builtin_value"),_SCS("is_using_builtin_value"));
+	ADD_PROPERTY(PropertyInfo(Variant::NIL,"value/builtin"),_SCS("set_builtin_value"),_SCS("get_builtin_value"));
+
+	BIND_CONSTANT( CALL_MODE_SELF );
+	BIND_CONSTANT( CALL_MODE_NODE_PATH);
+	BIND_CONSTANT( CALL_MODE_INSTANCE);
+}
+
+VisualScriptNodeInstance* VisualScriptPropertySet::instance(VScriptInstance* p_instance) {
+
+	return NULL;
+}
+
+VisualScriptPropertySet::VisualScriptPropertySet() {
+
+	call_mode=CALL_MODE_INSTANCE;
+	base_type="Object";
+
+}
+
+template<VisualScriptPropertySet::CallMode cmode>
+static Ref<VisualScriptNode> create_property_set_node(const String& p_name) {
+
+	Ref<VisualScriptPropertySet> node;
+	node.instance();
+	node->set_call_mode(cmode);
+	return node;
+}
+
+
+//////////////////////////////////////////
+////////////////SET//////////////////////
+//////////////////////////////////////////
+
+int VisualScriptPropertyGet::get_output_sequence_port_count() const {
+
+	return 1;
+}
+
+bool VisualScriptPropertyGet::has_input_sequence_port() const{
+
+	return true;
+}
+
+Node *VisualScriptPropertyGet::_get_base_node() const {
+
+#ifdef TOOLS_ENABLED
+	Ref<Script> script = get_visual_script();
+	if (!script.is_valid())
+		return NULL;
+
+	MainLoop * main_loop = OS::get_singleton()->get_main_loop();
+	if (!main_loop)
+		return NULL;
+
+	SceneTree *scene_tree = main_loop->cast_to<SceneTree>();
+
+	if (!scene_tree)
+		return NULL;
+
+	Node *edited_scene = scene_tree->get_edited_scene_root();
+
+	if (!edited_scene)
+		return NULL;
+
+	Node* script_node = _find_script_node(edited_scene,edited_scene,script);
+
+	if (!script_node)
+		return NULL;
+
+	if (!script_node->has_node(base_path))
+		return NULL;
+
+	Node *path_to = script_node->get_node(base_path);
+
+	return path_to;
+#else
+
+	return NULL;
+#endif
+}
+
+StringName VisualScriptPropertyGet::_get_base_type() const {
+
+	if (call_mode==CALL_MODE_SELF && get_visual_script().is_valid())
+		return get_visual_script()->get_instance_base_type();
+	else if (call_mode==CALL_MODE_NODE_PATH && get_visual_script().is_valid()) {
+		Node *path = _get_base_node();
+		if (path)
+			return path->get_type();
+
+	}
+
+	return base_type;
+}
+
+int VisualScriptPropertyGet::get_input_value_port_count() const{
+
+	return 0;
+
+}
+int VisualScriptPropertyGet::get_output_value_port_count() const{
+
+	return 1;
+}
+
+String VisualScriptPropertyGet::get_output_sequence_port_text(int p_port) const {
+
+	return String();
+}
+
+PropertyInfo VisualScriptPropertyGet::get_input_value_port_info(int p_idx) const{
+
+	if (call_mode==CALL_MODE_INSTANCE) {
+		if (p_idx==0) {
+			PropertyInfo pi;
+			pi.type=Variant::OBJECT;
+			pi.name="instance";
+			return pi;
+		} else {
+			p_idx--;
+		}
+	}
+	return PropertyInfo();
+
+}
+
+PropertyInfo VisualScriptPropertyGet::get_output_value_port_info(int p_idx) const{
+
+
+
+#ifdef DEBUG_METHODS_ENABLED
+
+	//not very efficient but..
+
+
+	List<PropertyInfo> pinfo;
+
+	if (call_mode==CALL_MODE_NODE_PATH) {
+
+		Node *n = _get_base_node();
+		if (n) {
+			n->get_property_list(&pinfo);
+		} else {
+			ObjectTypeDB::get_property_list(_get_base_type(),&pinfo);
+		}
+	} else {
+		ObjectTypeDB::get_property_list(_get_base_type(),&pinfo);
+	}
+
+	for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+
+		if (E->get().name==property) {
+
+			PropertyInfo info=E->get();
+			info.name="";
+			return info;
+		}
+	}
+
+
+#endif
+
+	return PropertyInfo(Variant::NIL,"");
+}
+
+
+String VisualScriptPropertyGet::get_caption() const {
+
+	return "Get";
+}
+
+String VisualScriptPropertyGet::get_text() const {
+
+	return property;
+
+}
+
+void VisualScriptPropertyGet::set_base_type(const StringName& p_type) {
+
+	if (base_type==p_type)
+		return;
+
+	base_type=p_type;
+	_change_notify();
+	emit_signal("ports_changed");
+}
+
+StringName VisualScriptPropertyGet::get_base_type() const{
+
+	return base_type;
+}
+
+void VisualScriptPropertyGet::set_property(const StringName& p_type){
+
+	if (property==p_type)
+		return;
+
+	property=p_type;
+	_change_notify();
+	emit_signal("ports_changed");
+}
+StringName VisualScriptPropertyGet::get_property() const {
+
+
+	return property;
+}
+
+void VisualScriptPropertyGet::set_base_path(const NodePath& p_type) {
+
+	if (base_path==p_type)
+		return;
+
+	base_path=p_type;
+	_change_notify();
+	emit_signal("ports_changed");
+}
+
+NodePath VisualScriptPropertyGet::get_base_path() const {
+
+	return base_path;
+}
+
+
+void VisualScriptPropertyGet::set_call_mode(CallMode p_mode) {
+
+	if (call_mode==p_mode)
+		return;
+
+	call_mode=p_mode;
+	_change_notify();
+	emit_signal("ports_changed");
+
+}
+VisualScriptPropertyGet::CallMode VisualScriptPropertyGet::get_call_mode() const {
+
+	return call_mode;
+}
+
+void VisualScriptPropertyGet::_validate_property(PropertyInfo& property) const {
+
+	if (property.name=="property/base_type") {
+		if (call_mode!=CALL_MODE_INSTANCE) {
+			property.usage=0;
+		}
+	}
+
+
+	if (property.name=="property/node_path") {
+		if (call_mode!=CALL_MODE_NODE_PATH) {
+			property.usage=0;
+		} else {
+
+			Node *bnode = _get_base_node();
+			if (bnode) {
+				property.hint_string=bnode->get_path(); //convert to loong string
+			} else {
+
+			}
+		}
+	}
+
+	if (property.name=="property/property") {
+		property.hint=PROPERTY_HINT_ENUM;
+
+
+		List<PropertyInfo> pinfo;
+
+		if (call_mode==CALL_MODE_NODE_PATH) {
+
+			Node *n = _get_base_node();
+			if (n) {
+				n->get_property_list(&pinfo);
+			} else {
+				ObjectTypeDB::get_property_list(_get_base_type(),&pinfo);
+			}
+		} else {
+			ObjectTypeDB::get_property_list(_get_base_type(),&pinfo);
+		}
+
+		List<String> mstring;
+
+		for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+
+			if (E->get().usage&PROPERTY_USAGE_EDITOR)
+				mstring.push_back(E->get().name);
+		}
+
+		String ml;
+		for (List<String>::Element *E=mstring.front();E;E=E->next()) {
+
+			if (ml!=String())
+				ml+=",";
+			ml+=E->get();
+		}
+
+		property.hint_string=ml;
+	}
+
+}
+
+void VisualScriptPropertyGet::_bind_methods() {
+
+	ObjectTypeDB::bind_method(_MD("set_base_type","base_type"),&VisualScriptPropertyGet::set_base_type);
+	ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptPropertyGet::get_base_type);
+
+	ObjectTypeDB::bind_method(_MD("set_property","property"),&VisualScriptPropertyGet::set_property);
+	ObjectTypeDB::bind_method(_MD("get_property"),&VisualScriptPropertyGet::get_property);
+
+	ObjectTypeDB::bind_method(_MD("set_call_mode","mode"),&VisualScriptPropertyGet::set_call_mode);
+	ObjectTypeDB::bind_method(_MD("get_call_mode"),&VisualScriptPropertyGet::get_call_mode);
+
+	ObjectTypeDB::bind_method(_MD("set_base_path","base_path"),&VisualScriptPropertyGet::set_base_path);
+	ObjectTypeDB::bind_method(_MD("get_base_path"),&VisualScriptPropertyGet::get_base_path);
+
+
+
+	ADD_PROPERTY(PropertyInfo(Variant::INT,"property/set_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance"),_SCS("set_call_mode"),_SCS("get_call_mode"));
+	ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type"));
+	ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"property/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_base_path"),_SCS("get_base_path"));
+	ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/property"),_SCS("set_property"),_SCS("get_property"));
+
+	BIND_CONSTANT( CALL_MODE_SELF );
+	BIND_CONSTANT( CALL_MODE_NODE_PATH);
+	BIND_CONSTANT( CALL_MODE_INSTANCE);
+}
+
+VisualScriptNodeInstance* VisualScriptPropertyGet::instance(VScriptInstance* p_instance) {
+
+	return NULL;
+}
+
+VisualScriptPropertyGet::VisualScriptPropertyGet() {
+
+	call_mode=CALL_MODE_INSTANCE;
+	base_type="Object";
+
+}
+
+template<VisualScriptPropertyGet::CallMode cmode>
+static Ref<VisualScriptNode> create_property_get_node(const String& p_name) {
+
+	Ref<VisualScriptPropertyGet> node;
+	node.instance();
+	node->set_call_mode(cmode);
+	return node;
+}
+
+
+//////////////////////////////////////////
+////////////////SCRIPT CALL//////////////////////
+//////////////////////////////////////////
+
+int VisualScriptScriptCall::get_output_sequence_port_count() const {
+
+	return 1;
+}
+
+bool VisualScriptScriptCall::has_input_sequence_port() const{
+
+	return true;
+}
+
+Node *VisualScriptScriptCall::_get_base_node() const {
+
+#ifdef TOOLS_ENABLED
+	Ref<Script> script = get_visual_script();
+	if (!script.is_valid())
+		return NULL;
+
+	MainLoop * main_loop = OS::get_singleton()->get_main_loop();
+	if (!main_loop)
+		return NULL;
+
+	SceneTree *scene_tree = main_loop->cast_to<SceneTree>();
+
+	if (!scene_tree)
+		return NULL;
+
+	Node *edited_scene = scene_tree->get_edited_scene_root();
+
+	if (!edited_scene)
+		return NULL;
+
+	Node* script_node = _find_script_node(edited_scene,edited_scene,script);
+
+	if (!script_node)
+		return NULL;
+
+	if (!script_node->has_node(base_path))
+		return NULL;
+
+	Node *path_to = script_node->get_node(base_path);
+
+	return path_to;
+#else
+
+	return NULL;
+#endif
+}
+
+
+int VisualScriptScriptCall::get_input_value_port_count() const{
+
+
+	if (call_mode==CALL_MODE_SELF) {
+
+		Ref<VisualScript> vs = get_visual_script();
+		if (vs.is_valid()) {
+
+			if (!vs->has_function(function))
+				return 0;
+
+			int id = vs->get_function_node_id(function);
+			if (id<0)
+				return 0;
+
+			Ref<VisualScriptFunction> func = vs->get_node(function,id);
+
+			return func->get_argument_count();
+		}
+	} else {
+
+		Node*base = _get_base_node();
+		if (!base)
+			return 0;
+		Ref<Script> script = base->get_script();
+		if (!script.is_valid())
+			return 0;
+
+		List<MethodInfo> functions;
+		script->get_method_list(&functions);
+		for (List<MethodInfo>::Element *E=functions.front();E;E=E->next()) {
+			if (E->get().name==function) {
+				return E->get().arguments.size();
+			}
+		}
+
+	}
+
+
+	return 0;
+
+}
+int VisualScriptScriptCall::get_output_value_port_count() const{
+	return 1;
+}
+
+String VisualScriptScriptCall::get_output_sequence_port_text(int p_port) const {
+
+	return String();
+}
+
+PropertyInfo VisualScriptScriptCall::get_input_value_port_info(int p_idx) const{
+
+	if (call_mode==CALL_MODE_SELF) {
+
+		Ref<VisualScript> vs = get_visual_script();
+		if (vs.is_valid()) {
+
+			if (!vs->has_function(function))
+				return PropertyInfo();
+
+			int id = vs->get_function_node_id(function);
+			if (id<0)
+				return PropertyInfo();
+
+			Ref<VisualScriptFunction> func = vs->get_node(function,id);
+
+			if (p_idx>=func->get_argument_count())
+				return PropertyInfo();
+			return PropertyInfo(func->get_argument_type(p_idx),func->get_argument_name(p_idx));
+		}
+	} else {
+
+		Node*base = _get_base_node();
+		if (!base)
+			return PropertyInfo();
+		Ref<Script> script = base->get_script();
+		if (!script.is_valid())
+			return PropertyInfo();
+
+		List<MethodInfo> functions;
+		script->get_method_list(&functions);
+		for (List<MethodInfo>::Element *E=functions.front();E;E=E->next()) {
+			if (E->get().name==function) {
+				if (p_idx<0 || p_idx>=E->get().arguments.size())
+					return PropertyInfo();
+				return E->get().arguments[p_idx];
+			}
+		}
+
+	}
+
+	return PropertyInfo();
+
+}
+
+PropertyInfo VisualScriptScriptCall::get_output_value_port_info(int p_idx) const{
+
+	return PropertyInfo();
+}
+
+
+String VisualScriptScriptCall::get_caption() const {
+
+	return "ScriptCall";
+}
+
+String VisualScriptScriptCall::get_text() const {
+
+	return "  "+String(function)+"()";
+}
+
+
+
+void VisualScriptScriptCall::set_function(const StringName& p_type){
+
+	if (function==p_type)
+		return;
+
+	function=p_type;
+
+	_change_notify();
+	emit_signal("ports_changed");
+}
+StringName VisualScriptScriptCall::get_function() const {
+
+
+	return function;
+}
+
+void VisualScriptScriptCall::set_base_path(const NodePath& p_type) {
+
+	if (base_path==p_type)
+		return;
+
+	base_path=p_type;
+
+	_change_notify();
+	emit_signal("ports_changed");
+}
+
+NodePath VisualScriptScriptCall::get_base_path() const {
+
+	return base_path;
+}
+
+
+void VisualScriptScriptCall::set_call_mode(CallMode p_mode) {
+
+	if (call_mode==p_mode)
+		return;
+
+	call_mode=p_mode;
+
+	_change_notify();
+	emit_signal("ports_changed");
+
+}
+VisualScriptScriptCall::CallMode VisualScriptScriptCall::get_call_mode() const {
+
+	return call_mode;
+}
+
+void VisualScriptScriptCall::_validate_property(PropertyInfo& property) const {
+
+
+
+	if (property.name=="function/node_path") {
+		if (call_mode!=CALL_MODE_NODE_PATH) {
+			property.usage=0;
+		} else {
+
+			Node *bnode = _get_base_node();
+			if (bnode) {
+				property.hint_string=bnode->get_path(); //convert to loong string
+			} else {
+
+			}
+		}
+	}
+
+	if (property.name=="function/function") {
+		property.hint=PROPERTY_HINT_ENUM;
+
+
+		List<MethodInfo> methods;
+
+		if (call_mode==CALL_MODE_SELF) {
+
+			Ref<VisualScript> vs = get_visual_script();
+			if (vs.is_valid()) {
+
+				vs->get_method_list(&methods);
+
+			}
+		} else {
+
+			Node*base = _get_base_node();
+			if (!base)
+				return;
+			Ref<Script> script = base->get_script();
+			if (!script.is_valid())
+				return;
+
+			script->get_method_list(&methods);
+
+		}
+
+		List<String> mstring;
+		for (List<MethodInfo>::Element *E=methods.front();E;E=E->next()) {
+			if (E->get().name.begins_with("_"))
+				continue;
+			mstring.push_back(E->get().name.get_slice(":",0));
+		}
+
+		mstring.sort();
+
+		String ml;
+		for (List<String>::Element *E=mstring.front();E;E=E->next()) {
+
+			if (ml!=String())
+				ml+=",";
+			ml+=E->get();
+		}
+
+		property.hint_string=ml;
+	}
+
+}
+
+
+void VisualScriptScriptCall::_bind_methods() {
+
+	ObjectTypeDB::bind_method(_MD("set_function","function"),&VisualScriptScriptCall::set_function);
+	ObjectTypeDB::bind_method(_MD("get_function"),&VisualScriptScriptCall::get_function);
+
+	ObjectTypeDB::bind_method(_MD("set_call_mode","mode"),&VisualScriptScriptCall::set_call_mode);
+	ObjectTypeDB::bind_method(_MD("get_call_mode"),&VisualScriptScriptCall::get_call_mode);
+
+	ObjectTypeDB::bind_method(_MD("set_base_path","base_path"),&VisualScriptScriptCall::set_base_path);
+	ObjectTypeDB::bind_method(_MD("get_base_path"),&VisualScriptScriptCall::get_base_path);
+
+
+	ADD_PROPERTY(PropertyInfo(Variant::INT,"function/call_mode",PROPERTY_HINT_ENUM,"Self,Node Path"),_SCS("set_call_mode"),_SCS("get_call_mode"));
+	ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"function/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_base_path"),_SCS("get_base_path"));
+	ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/function"),_SCS("set_function"),_SCS("get_function"));
+
+	BIND_CONSTANT( CALL_MODE_SELF );
+	BIND_CONSTANT( CALL_MODE_NODE_PATH);
+
+}
+
+VisualScriptNodeInstance* VisualScriptScriptCall::instance(VScriptInstance* p_instance) {
+
+	return NULL;
+}
+
+VisualScriptScriptCall::VisualScriptScriptCall() {
+
+	call_mode=CALL_MODE_SELF;
+
+
+}
+
+template<VisualScriptScriptCall::CallMode cmode>
+static Ref<VisualScriptNode> create_script_call_node(const String& p_name) {
+
+	Ref<VisualScriptScriptCall> node;
+	node.instance();
+	node->set_call_mode(cmode);
+	return node;
+}
+
+
+//////////////////////////////////////////
+////////////////SCRIPT CALL//////////////////////
+//////////////////////////////////////////
+
+int VisualScriptEmitSignal::get_output_sequence_port_count() const {
+
+	return 1;
+}
+
+bool VisualScriptEmitSignal::has_input_sequence_port() const{
+
+	return true;
+}
+
+
+int VisualScriptEmitSignal::get_input_value_port_count() const{
+
+	Ref<VisualScript> vs = get_visual_script();
+	if (vs.is_valid()) {
+
+		if (!vs->has_custom_signal(name))
+			return 0;
+
+		return vs->custom_signal_get_argument_count(name);
+	}
+
+	return 0;
+
+}
+int VisualScriptEmitSignal::get_output_value_port_count() const{
+	return 0;
+}
+
+String VisualScriptEmitSignal::get_output_sequence_port_text(int p_port) const {
+
+	return String();
+}
+
+PropertyInfo VisualScriptEmitSignal::get_input_value_port_info(int p_idx) const{
+
+	Ref<VisualScript> vs = get_visual_script();
+	if (vs.is_valid()) {
+
+		if (!vs->has_custom_signal(name))
+			return PropertyInfo();
+
+		return PropertyInfo(vs->custom_signal_get_argument_type(name,p_idx),vs->custom_signal_get_argument_name(name,p_idx));
+	}
+
+	return PropertyInfo();
+
+}
+
+PropertyInfo VisualScriptEmitSignal::get_output_value_port_info(int p_idx) const{
+
+	return PropertyInfo();
+}
+
+
+String VisualScriptEmitSignal::get_caption() const {
+
+	return "EmitSignal";
+}
+
+String VisualScriptEmitSignal::get_text() const {
+
+	return "emit "+String(name);
+}
+
+
+
+void VisualScriptEmitSignal::set_signal(const StringName& p_type){
+
+	if (name==p_type)
+		return;
+
+	name=p_type;
+
+	_change_notify();
+	emit_signal("ports_changed");
+}
+StringName VisualScriptEmitSignal::get_signal() const {
+
+
+	return name;
+}
+
+
+void VisualScriptEmitSignal::_validate_property(PropertyInfo& property) const {
+
+
+
+	if (property.name=="signal/signal") {
+		property.hint=PROPERTY_HINT_ENUM;
+
+
+		List<StringName> sigs;
+
+		Ref<VisualScript> vs = get_visual_script();
+		if (vs.is_valid()) {
+
+			vs->get_custom_signal_list(&sigs);
+
+		}
+
+		String ml;
+		for (List<StringName>::Element *E=sigs.front();E;E=E->next()) {
+
+			if (ml!=String())
+				ml+=",";
+			ml+=E->get();
+		}
+
+		property.hint_string=ml;
+	}
+
+}
+
+
+void VisualScriptEmitSignal::_bind_methods() {
+
+	ObjectTypeDB::bind_method(_MD("set_signal","name"),&VisualScriptEmitSignal::set_signal);
+	ObjectTypeDB::bind_method(_MD("get_signal"),&VisualScriptEmitSignal::get_signal);
+
+
+	ADD_PROPERTY(PropertyInfo(Variant::STRING,"signal/signal"),_SCS("set_signal"),_SCS("get_signal"));
+
+
+}
+
+VisualScriptNodeInstance* VisualScriptEmitSignal::instance(VScriptInstance* p_instance) {
+
+	return NULL;
+}
+
+VisualScriptEmitSignal::VisualScriptEmitSignal() {
+}
+
+void register_visual_script_func_nodes() {
+
+	VisualScriptLanguage::singleton->add_register_func("functions/call_method/call",create_function_call_node<VisualScriptFunctionCall::CALL_MODE_INSTANCE>);
+	VisualScriptLanguage::singleton->add_register_func("functions/call_method/call_in_self",create_function_call_node<VisualScriptFunctionCall::CALL_MODE_SELF>);
+	VisualScriptLanguage::singleton->add_register_func("functions/call_method/call_in_node",create_function_call_node<VisualScriptFunctionCall::CALL_MODE_NODE_PATH>);
+
+	VisualScriptLanguage::singleton->add_register_func("functions/set_property/set",create_property_set_node<VisualScriptPropertySet::CALL_MODE_INSTANCE>);
+	VisualScriptLanguage::singleton->add_register_func("functions/set_property/set_in_self",create_property_set_node<VisualScriptPropertySet::CALL_MODE_SELF>);
+	VisualScriptLanguage::singleton->add_register_func("functions/set_property/set_in_node",create_property_set_node<VisualScriptPropertySet::CALL_MODE_NODE_PATH>);
+
+	VisualScriptLanguage::singleton->add_register_func("functions/get_property/get",create_property_get_node<VisualScriptPropertyGet::CALL_MODE_INSTANCE>);
+	VisualScriptLanguage::singleton->add_register_func("functions/get_property/get_from_self",create_property_get_node<VisualScriptPropertyGet::CALL_MODE_SELF>);
+	VisualScriptLanguage::singleton->add_register_func("functions/get_property/get_from_node",create_property_get_node<VisualScriptPropertyGet::CALL_MODE_NODE_PATH>);
+
+	VisualScriptLanguage::singleton->add_register_func("functions/script/script_call",create_script_call_node<VisualScriptScriptCall::CALL_MODE_SELF>);
+	VisualScriptLanguage::singleton->add_register_func("functions/script/script_call_in_node",create_script_call_node<VisualScriptScriptCall::CALL_MODE_NODE_PATH>);
+	VisualScriptLanguage::singleton->add_register_func("functions/script/emit_signal",create_node_generic<VisualScriptEmitSignal>);
+
+
+}

+ 325 - 0
modules/visual_script/visual_script_func_nodes.h

@@ -0,0 +1,325 @@
+#ifndef VISUAL_SCRIPT_FUNC_NODES_H
+#define VISUAL_SCRIPT_FUNC_NODES_H
+
+#include "visual_script.h"
+
+
+class VisualScriptFunctionCall : public VisualScriptNode {
+
+	OBJ_TYPE(VisualScriptFunctionCall,VisualScriptNode)
+public:
+	enum CallMode {
+		CALL_MODE_SELF,
+		CALL_MODE_NODE_PATH,
+		CALL_MODE_INSTANCE,
+	};
+private:
+
+	CallMode call_mode;
+	StringName base_type;
+	NodePath base_path;
+	StringName function;
+	int use_default_args;
+
+	Node *_get_base_node() const;
+	StringName _get_base_type() const;
+
+	void _update_defargs();
+protected:
+	virtual void _validate_property(PropertyInfo& property) const;
+
+	static void _bind_methods();
+
+public:
+
+	virtual int get_output_sequence_port_count() const;
+	virtual bool has_input_sequence_port() const;
+
+
+	virtual String get_output_sequence_port_text(int p_port) const;
+
+
+	virtual int get_input_value_port_count() const;
+	virtual int get_output_value_port_count() const;
+
+
+	virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+	virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+	virtual String get_caption() const;
+	virtual String get_text() const;
+
+	void set_base_type(const StringName& p_type);
+	StringName get_base_type() const;
+
+	void set_function(const StringName& p_type);
+	StringName get_function() const;
+
+	void set_base_path(const NodePath& p_type);
+	NodePath get_base_path() const;
+
+	void set_call_mode(CallMode p_mode);
+	CallMode get_call_mode() const;
+
+	void set_use_default_args(int p_amount);
+	int get_use_default_args() const;
+
+	virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance);
+
+	VisualScriptFunctionCall();
+};
+
+VARIANT_ENUM_CAST(VisualScriptFunctionCall::CallMode );
+
+
+class VisualScriptPropertySet : public VisualScriptNode {
+
+	OBJ_TYPE(VisualScriptPropertySet,VisualScriptNode)
+public:
+	enum CallMode {
+		CALL_MODE_SELF,
+		CALL_MODE_NODE_PATH,
+		CALL_MODE_INSTANCE,
+	};
+private:
+
+	CallMode call_mode;
+	StringName base_type;
+	NodePath base_path;
+	StringName property;
+	bool use_builtin_value;
+	Variant builtin_value;
+
+	Node *_get_base_node() const;
+	StringName _get_base_type() const;
+
+
+protected:
+	virtual void _validate_property(PropertyInfo& property) const;
+
+	static void _bind_methods();
+
+public:
+
+	virtual int get_output_sequence_port_count() const;
+	virtual bool has_input_sequence_port() const;
+
+
+	virtual String get_output_sequence_port_text(int p_port) const;
+
+
+	virtual int get_input_value_port_count() const;
+	virtual int get_output_value_port_count() const;
+
+
+	virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+	virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+	virtual String get_caption() const;
+	virtual String get_text() const;
+
+	void set_base_type(const StringName& p_type);
+	StringName get_base_type() const;
+
+	void set_property(const StringName& p_type);
+	StringName get_property() const;
+
+	void set_base_path(const NodePath& p_type);
+	NodePath get_base_path() const;
+
+	void set_call_mode(CallMode p_mode);
+	CallMode get_call_mode() const;
+
+	void set_use_builtin_value(bool p_use);
+	bool is_using_builtin_value() const;
+
+	void set_builtin_value(const Variant &p_value);
+	Variant get_builtin_value() const;
+
+	virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance);
+
+	VisualScriptPropertySet();
+};
+
+VARIANT_ENUM_CAST(VisualScriptPropertySet::CallMode );
+
+
+class VisualScriptPropertyGet : public VisualScriptNode {
+
+	OBJ_TYPE(VisualScriptPropertyGet,VisualScriptNode)
+public:
+	enum CallMode {
+		CALL_MODE_SELF,
+		CALL_MODE_NODE_PATH,
+		CALL_MODE_INSTANCE,
+	};
+private:
+
+	CallMode call_mode;
+	StringName base_type;
+	NodePath base_path;
+	StringName property;
+
+
+	Node *_get_base_node() const;
+	StringName _get_base_type() const;
+
+
+protected:
+	virtual void _validate_property(PropertyInfo& property) const;
+
+	static void _bind_methods();
+
+public:
+
+	virtual int get_output_sequence_port_count() const;
+	virtual bool has_input_sequence_port() const;
+
+
+	virtual String get_output_sequence_port_text(int p_port) const;
+
+
+	virtual int get_input_value_port_count() const;
+	virtual int get_output_value_port_count() const;
+
+
+	virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+	virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+	virtual String get_caption() const;
+	virtual String get_text() const;
+
+	void set_base_type(const StringName& p_type);
+	StringName get_base_type() const;
+
+	void set_property(const StringName& p_type);
+	StringName get_property() const;
+
+	void set_base_path(const NodePath& p_type);
+	NodePath get_base_path() const;
+
+	void set_call_mode(CallMode p_mode);
+	CallMode get_call_mode() const;
+
+	virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance);
+
+	VisualScriptPropertyGet();
+};
+
+
+
+
+
+VARIANT_ENUM_CAST(VisualScriptPropertyGet::CallMode );
+
+
+
+class VisualScriptScriptCall : public VisualScriptNode {
+
+	OBJ_TYPE(VisualScriptScriptCall,VisualScriptNode)
+public:
+	enum CallMode {
+		CALL_MODE_SELF,
+		CALL_MODE_NODE_PATH,
+	};
+private:
+
+	CallMode call_mode;
+	NodePath base_path;
+	StringName function;
+
+
+	Node *_get_base_node() const;
+
+
+protected:
+	virtual void _validate_property(PropertyInfo& property) const;
+
+	static void _bind_methods();
+
+public:
+
+	virtual int get_output_sequence_port_count() const;
+	virtual bool has_input_sequence_port() const;
+
+
+	virtual String get_output_sequence_port_text(int p_port) const;
+
+
+	virtual int get_input_value_port_count() const;
+	virtual int get_output_value_port_count() const;
+
+
+	virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+	virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+	virtual String get_caption() const;
+	virtual String get_text() const;
+
+	void set_function(const StringName& p_type);
+	StringName get_function() const;
+
+	void set_base_path(const NodePath& p_type);
+	NodePath get_base_path() const;
+
+	void set_call_mode(CallMode p_mode);
+	CallMode get_call_mode() const;
+
+
+
+	virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance);
+
+	VisualScriptScriptCall();
+};
+
+VARIANT_ENUM_CAST(VisualScriptScriptCall::CallMode );
+
+
+
+
+class VisualScriptEmitSignal : public VisualScriptNode {
+
+	OBJ_TYPE(VisualScriptEmitSignal,VisualScriptNode)
+
+private:
+
+	StringName name;
+
+
+protected:
+	virtual void _validate_property(PropertyInfo& property) const;
+
+	static void _bind_methods();
+
+public:
+
+	virtual int get_output_sequence_port_count() const;
+	virtual bool has_input_sequence_port() const;
+
+
+	virtual String get_output_sequence_port_text(int p_port) const;
+
+
+	virtual int get_input_value_port_count() const;
+	virtual int get_output_value_port_count() const;
+
+
+	virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+	virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+	virtual String get_caption() const;
+	virtual String get_text() const;
+
+	void set_signal(const StringName& p_type);
+	StringName get_signal() const;
+
+	virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance);
+
+	VisualScriptEmitSignal();
+};
+
+
+
+void register_visual_script_func_nodes();
+
+#endif // VISUAL_SCRIPT_FUNC_NODES_H

+ 1297 - 0
modules/visual_script/visual_script_nodes.cpp

@@ -0,0 +1,1297 @@
+#include "visual_script_nodes.h"
+#include "global_constants.h"
+#include "globals.h"
+#include "scene/main/scene_main_loop.h"
+#include "os/os.h"
+#include "scene/main/node.h"
+
+//////////////////////////////////////////
+////////////////FUNCTION//////////////////
+//////////////////////////////////////////
+
+
+bool  VisualScriptFunction::_set(const StringName& p_name, const Variant& p_value) {
+
+
+	if (p_name=="argument_count") {
+
+		int new_argc=p_value;
+		int argc = arguments.size();
+		if (argc==new_argc)
+			return true;
+
+		arguments.resize(new_argc);
+
+		for(int i=argc;i<new_argc;i++) {
+			arguments[i].name="arg"+itos(i+1);
+			arguments[i].type=Variant::NIL;
+		}
+		emit_signal("ports_changed");
+		_change_notify();
+		return true;
+	}
+	if (String(p_name).begins_with("argument/")) {
+		int idx = String(p_name).get_slice("/",1).to_int()-1;
+		ERR_FAIL_INDEX_V(idx,arguments.size(),false);
+		String what = String(p_name).get_slice("/",2);
+		if (what=="type") {
+
+			Variant::Type new_type = Variant::Type(int(p_value));
+			arguments[idx].type=new_type;
+			emit_signal("ports_changed");
+
+			return true;
+		}
+
+		if (what=="name") {
+
+			arguments[idx].name=p_value;
+			emit_signal("ports_changed");
+			return true;
+		}
+
+
+	}
+
+
+	return false;
+}
+
+bool  VisualScriptFunction::_get(const StringName& p_name,Variant &r_ret) const {
+
+
+	if (p_name=="argument_count") {
+		r_ret = arguments.size();
+		return true;
+	}
+	if (String(p_name).begins_with("argument/")) {
+		int idx = String(p_name).get_slice("/",1).to_int()-1;
+		ERR_FAIL_INDEX_V(idx,arguments.size(),false);
+		String what = String(p_name).get_slice("/",2);
+		if (what=="type") {
+			r_ret = arguments[idx].type;
+			return true;
+		}
+		if (what=="name") {
+			r_ret = arguments[idx].name;
+			return true;
+		}
+
+
+
+	}
+
+	return false;
+}
+void  VisualScriptFunction::_get_property_list( List<PropertyInfo> *p_list) const {
+
+
+	p_list->push_back(PropertyInfo(Variant::INT,"argument_count",PROPERTY_HINT_RANGE,"0,256"));
+	String argt="Variant";
+	for(int i=1;i<Variant::VARIANT_MAX;i++) {
+		argt+=","+Variant::get_type_name(Variant::Type(i));
+	}
+
+	for(int i=0;i<arguments.size();i++) {
+		p_list->push_back(PropertyInfo(Variant::INT,"argument/"+itos(i+1)+"/type",PROPERTY_HINT_ENUM,argt));
+		p_list->push_back(PropertyInfo(Variant::STRING,"argument/"+itos(i+1)+"/name"));
+	}
+}
+
+
+int VisualScriptFunction::get_output_sequence_port_count() const {
+
+	return 1;
+}
+
+bool VisualScriptFunction::has_input_sequence_port() const{
+
+	return false;
+}
+
+int VisualScriptFunction::get_input_value_port_count() const{
+
+	return 0;
+}
+int VisualScriptFunction::get_output_value_port_count() const{
+
+	return arguments.size();
+}
+
+String VisualScriptFunction::get_output_sequence_port_text(int p_port) const {
+
+	return String();
+}
+
+PropertyInfo VisualScriptFunction::get_input_value_port_info(int p_idx) const{
+
+	ERR_FAIL_V(PropertyInfo());
+	return PropertyInfo();
+}
+PropertyInfo VisualScriptFunction::get_output_value_port_info(int p_idx) const{
+
+	ERR_FAIL_INDEX_V(p_idx,arguments.size(),PropertyInfo());
+	PropertyInfo out;
+	out.type=arguments[p_idx].type;
+	out.name=arguments[p_idx].name;
+	return out;
+}
+
+String VisualScriptFunction::get_caption() const {
+
+	return "Function";
+}
+
+String VisualScriptFunction::get_text() const {
+
+	return get_name(); //use name as function name I guess
+}
+
+void VisualScriptFunction::add_argument(Variant::Type p_type,const String& p_name,int p_index){
+
+	Argument arg;
+	arg.name=p_name;
+	arg.type=p_type;
+	if (p_index>=0)
+		arguments.insert(p_index,arg);
+	else
+		arguments.push_back(arg);
+
+	emit_signal("ports_changed");
+
+}
+void VisualScriptFunction::set_argument_type(int p_argidx,Variant::Type p_type){
+
+	ERR_FAIL_INDEX(p_argidx,arguments.size());
+
+	arguments[p_argidx].type=p_type;
+	emit_signal("ports_changed");
+}
+Variant::Type VisualScriptFunction::get_argument_type(int p_argidx) const {
+
+	ERR_FAIL_INDEX_V(p_argidx,arguments.size(),Variant::NIL);
+	return arguments[p_argidx].type;
+
+}
+void VisualScriptFunction::set_argument_name(int p_argidx,const String& p_name) {
+
+	ERR_FAIL_INDEX(p_argidx,arguments.size());
+
+	arguments[p_argidx].name=p_name;
+	emit_signal("ports_changed");
+
+}
+String VisualScriptFunction::get_argument_name(int p_argidx) const {
+
+	ERR_FAIL_INDEX_V(p_argidx,arguments.size(),String());
+	return arguments[p_argidx].name;
+
+}
+void VisualScriptFunction::remove_argument(int p_argidx) {
+
+	ERR_FAIL_INDEX(p_argidx,arguments.size());
+
+	arguments.remove(p_argidx);
+	emit_signal("ports_changed");
+
+}
+
+int VisualScriptFunction::get_argument_count() const {
+
+	return arguments.size();
+}
+
+
+VisualScriptNodeInstance* VisualScriptFunction::instance(VScriptInstance* p_instance) {
+
+	return NULL;
+}
+
+VisualScriptFunction::VisualScriptFunction() {
+
+
+}
+
+
+//////////////////////////////////////////
+////////////////OPERATOR//////////////////
+//////////////////////////////////////////
+
+int VisualScriptOperator::get_output_sequence_port_count() const {
+
+	return 1;
+}
+
+bool VisualScriptOperator::has_input_sequence_port() const{
+
+	return true;
+}
+
+int VisualScriptOperator::get_input_value_port_count() const{
+
+	return (op==Variant::OP_BIT_NEGATE || op==Variant::OP_NOT || op==Variant::OP_NEGATE) ? 1 : 2;
+}
+int VisualScriptOperator::get_output_value_port_count() const{
+
+	return 1;
+}
+
+String VisualScriptOperator::get_output_sequence_port_text(int p_port) const {
+
+	return String();
+}
+
+PropertyInfo VisualScriptOperator::get_input_value_port_info(int p_idx) const{
+
+	static const Variant::Type port_types[Variant::OP_MAX][2]={
+		{Variant::NIL,Variant::NIL}, //OP_EQUAL,
+		{Variant::NIL,Variant::NIL}, //OP_NOT_EQUAL,
+		{Variant::NIL,Variant::NIL}, //OP_LESS,
+		{Variant::NIL,Variant::NIL}, //OP_LESS_EQUAL,
+		{Variant::NIL,Variant::NIL}, //OP_GREATER,
+		{Variant::NIL,Variant::NIL}, //OP_GREATER_EQUAL,
+		//mathematic
+		{Variant::NIL,Variant::NIL}, //OP_ADD,
+		{Variant::NIL,Variant::NIL}, //OP_SUBSTRACT,
+		{Variant::NIL,Variant::NIL}, //OP_MULTIPLY,
+		{Variant::NIL,Variant::NIL}, //OP_DIVIDE,
+		{Variant::NIL,Variant::NIL}, //OP_NEGATE,
+		{Variant::INT,Variant::INT}, //OP_MODULE,
+		{Variant::STRING,Variant::STRING}, //OP_STRING_CONCAT,
+		//bitwise
+		{Variant::INT,Variant::INT}, //OP_SHIFT_LEFT,
+		{Variant::INT,Variant::INT}, //OP_SHIFT_RIGHT,
+		{Variant::INT,Variant::INT}, //OP_BIT_AND,
+		{Variant::INT,Variant::INT}, //OP_BIT_OR,
+		{Variant::INT,Variant::INT}, //OP_BIT_XOR,
+		{Variant::INT,Variant::INT}, //OP_BIT_NEGATE,
+		//logic
+		{Variant::BOOL,Variant::BOOL}, //OP_AND,
+		{Variant::BOOL,Variant::BOOL}, //OP_OR,
+		{Variant::BOOL,Variant::BOOL}, //OP_XOR,
+		{Variant::BOOL,Variant::BOOL}, //OP_NOT,
+		//containment
+		{Variant::NIL,Variant::NIL} //OP_IN,
+	};
+
+	ERR_FAIL_INDEX_V(p_idx,Variant::OP_MAX,PropertyInfo());
+
+	PropertyInfo pinfo;
+	pinfo.name=p_idx==0?"A":"B";
+	pinfo.type=port_types[op][p_idx];
+	return pinfo;
+}
+PropertyInfo VisualScriptOperator::get_output_value_port_info(int p_idx) const{
+	static const Variant::Type port_types[Variant::OP_MAX]={
+		//comparation
+		Variant::BOOL, //OP_EQUAL,
+		Variant::BOOL, //OP_NOT_EQUAL,
+		Variant::BOOL, //OP_LESS,
+		Variant::BOOL, //OP_LESS_EQUAL,
+		Variant::BOOL, //OP_GREATER,
+		Variant::BOOL, //OP_GREATER_EQUAL,
+		//mathematic
+		Variant::NIL, //OP_ADD,
+		Variant::NIL, //OP_SUBSTRACT,
+		Variant::NIL, //OP_MULTIPLY,
+		Variant::NIL, //OP_DIVIDE,
+		Variant::NIL, //OP_NEGATE,
+		Variant::INT, //OP_MODULE,
+		Variant::STRING, //OP_STRING_CONCAT,
+		//bitwise
+		Variant::INT, //OP_SHIFT_LEFT,
+		Variant::INT, //OP_SHIFT_RIGHT,
+		Variant::INT, //OP_BIT_AND,
+		Variant::INT, //OP_BIT_OR,
+		Variant::INT, //OP_BIT_XOR,
+		Variant::INT, //OP_BIT_NEGATE,
+		//logic
+		Variant::BOOL, //OP_AND,
+		Variant::BOOL, //OP_OR,
+		Variant::BOOL, //OP_XOR,
+		Variant::BOOL, //OP_NOT,
+		//containment
+		Variant::BOOL //OP_IN,
+	};
+
+	PropertyInfo pinfo;
+	pinfo.name="";
+	pinfo.type=port_types[op];
+	return pinfo;
+
+}
+
+static const char* op_names[]={
+	//comparation
+	"Equal", //OP_EQUAL,
+	"NotEqual", //OP_NOT_EQUAL,
+	"Less", //OP_LESS,
+	"LessEqual", //OP_LESS_EQUAL,
+	"Greater", //OP_GREATER,
+	"GreaterEq", //OP_GREATER_EQUAL,
+	//mathematic
+	"Add", //OP_ADD,
+	"Subtract", //OP_SUBSTRACT,
+	"Multiply", //OP_MULTIPLY,
+	"Divide", //OP_DIVIDE,
+	"Negate", //OP_NEGATE,
+	"Remainder", //OP_MODULE,
+	"Concat", //OP_STRING_CONCAT,
+	//bitwise
+	"ShiftLeft", //OP_SHIFT_LEFT,
+	"ShiftRight", //OP_SHIFT_RIGHT,
+	"BitAnd", //OP_BIT_AND,
+	"BitOr", //OP_BIT_OR,
+	"BitXor", //OP_BIT_XOR,
+	"BitNeg", //OP_BIT_NEGATE,
+	//logic
+	"And", //OP_AND,
+	"Or", //OP_OR,
+	"Xor", //OP_XOR,
+	"Not", //OP_NOT,
+	//containment
+	"In", //OP_IN,
+};
+
+String VisualScriptOperator::get_caption() const {
+
+
+
+	return op_names[op];
+}
+
+String VisualScriptOperator::get_text() const {
+
+	static const wchar_t* op_names[]={
+		//comparation
+		L"A = B", //OP_EQUAL,
+		L"A \u2260 B", //OP_NOT_EQUAL,
+		L"A < B", //OP_LESS,
+		L"A \u2264 B", //OP_LESS_EQUAL,
+		L"A > B", //OP_GREATER,
+		L"A \u2265 B", //OP_GREATER_EQUAL,
+		//mathematic
+		L"A + B", //OP_ADD,
+		L"A - B", //OP_SUBSTRACT,
+		L"A x B", //OP_MULTIPLY,
+		L"A \u00F7 B", //OP_DIVIDE,
+		L"\u00AC A", //OP_NEGATE,
+		L"A mod B", //OP_MODULE,
+		L"A .. B", //OP_STRING_CONCAT,
+		//bitwise
+		L"A << B", //OP_SHIFT_LEFT,
+		L"A >> B", //OP_SHIFT_RIGHT,
+		L"A & B", //OP_BIT_AND,
+		L"A | B", //OP_BIT_OR,
+		L"A ^ B", //OP_BIT_XOR,
+		L"~A", //OP_BIT_NEGATE,
+		//logic
+		L"A and B", //OP_AND,
+		L"A or B", //OP_OR,
+		L"A xor B", //OP_XOR,
+		L"not A", //OP_NOT,
+
+	};
+	return op_names[op];
+}
+
+void VisualScriptOperator::set_operator(Variant::Operator p_op) {
+
+	if (op==p_op)
+		return;
+	op=p_op;
+	emit_signal("ports_changed");
+
+}
+
+Variant::Operator VisualScriptOperator::get_operator() const{
+
+	return op;
+}
+
+
+void VisualScriptOperator::_bind_methods() {
+
+	ObjectTypeDB::bind_method(_MD("set_operator","op"),&VisualScriptOperator::set_operator);
+	ObjectTypeDB::bind_method(_MD("get_operator"),&VisualScriptOperator::get_operator);
+
+	String types;
+	for(int i=0;i<Variant::OP_MAX;i++) {
+		if (i>0)
+			types+=",";
+		types+=op_names[i];
+	}
+	ADD_PROPERTY(PropertyInfo(Variant::INT,"operator_value/type",PROPERTY_HINT_ENUM,types),_SCS("set_operator"),_SCS("get_operator"));
+
+}
+
+VisualScriptNodeInstance* VisualScriptOperator::instance(VScriptInstance* p_instance) {
+
+	return NULL;
+}
+
+VisualScriptOperator::VisualScriptOperator() {
+
+	op=Variant::OP_ADD;
+}
+
+
+
+template<Variant::Operator OP>
+static Ref<VisualScriptNode> create_op_node(const String& p_name) {
+
+	Ref<VisualScriptOperator> node;
+	node.instance();
+	node->set_operator(OP);
+	return node;
+}
+
+//////////////////////////////////////////
+////////////////VARIABLE//////////////////
+//////////////////////////////////////////
+
+int VisualScriptVariable::get_output_sequence_port_count() const {
+
+	return 1;
+}
+
+bool VisualScriptVariable::has_input_sequence_port() const{
+
+	return true;
+}
+
+int VisualScriptVariable::get_input_value_port_count() const{
+
+	return 1;
+}
+int VisualScriptVariable::get_output_value_port_count() const{
+
+	return 1;
+}
+
+String VisualScriptVariable::get_output_sequence_port_text(int p_port) const {
+
+	return String();
+}
+
+PropertyInfo VisualScriptVariable::get_input_value_port_info(int p_idx) const{
+
+	PropertyInfo pinfo;
+	pinfo.name="set";
+	if (get_visual_script().is_valid() && get_visual_script()->has_variable(variable)) {
+		PropertyInfo vinfo = get_visual_script()->get_variable_info(variable);
+		pinfo.type=vinfo.type;
+		pinfo.hint=vinfo.hint;
+		pinfo.hint_string=vinfo.hint_string;
+	}
+	return pinfo;
+}
+
+PropertyInfo VisualScriptVariable::get_output_value_port_info(int p_idx) const{
+
+	PropertyInfo pinfo;
+	pinfo.name="get";
+	if (get_visual_script().is_valid() && get_visual_script()->has_variable(variable)) {
+		PropertyInfo vinfo = get_visual_script()->get_variable_info(variable);
+		pinfo.type=vinfo.type;
+		pinfo.hint=vinfo.hint;
+		pinfo.hint_string=vinfo.hint_string;
+	}
+	return pinfo;
+}
+
+
+String VisualScriptVariable::get_caption() const {
+
+	return "Variable";
+}
+
+String VisualScriptVariable::get_text() const {
+
+	return variable;
+}
+
+void VisualScriptVariable::set_variable(StringName p_variable) {
+
+	if (variable==p_variable)
+		return;
+	variable=p_variable;
+	emit_signal("ports_changed");
+
+}
+
+StringName VisualScriptVariable::get_variable() const{
+
+	return variable;
+}
+
+void VisualScriptVariable::_validate_property(PropertyInfo& property) const {
+
+	if (property.name=="variable/name" && get_visual_script().is_valid()) {
+		Ref<VisualScript> vs = get_visual_script();
+		List<StringName> vars;
+		vs->get_variable_list(&vars);
+
+		String vhint;
+		for (List<StringName>::Element *E=vars.front();E;E=E->next()) {
+			if (vhint!=String())
+				vhint+=",";
+
+			vhint+=E->get().operator String();
+		}
+
+		property.hint=PROPERTY_HINT_ENUM;
+		property.hint_string=vhint;
+	}
+}
+
+void VisualScriptVariable::_bind_methods() {
+
+	ObjectTypeDB::bind_method(_MD("set_variable","name"),&VisualScriptVariable::set_variable);
+	ObjectTypeDB::bind_method(_MD("get_variable"),&VisualScriptVariable::get_variable);
+
+
+	ADD_PROPERTY(PropertyInfo(Variant::STRING,"variable/name"),_SCS("set_variable"),_SCS("get_variable"));
+
+}
+
+VisualScriptNodeInstance* VisualScriptVariable::instance(VScriptInstance* p_instance) {
+
+	return NULL;
+}
+
+VisualScriptVariable::VisualScriptVariable() {
+
+
+}
+
+
+
+//////////////////////////////////////////
+////////////////CONSTANT//////////////////
+//////////////////////////////////////////
+
+int VisualScriptConstant::get_output_sequence_port_count() const {
+
+	return 0;
+}
+
+bool VisualScriptConstant::has_input_sequence_port() const{
+
+	return false;
+}
+
+int VisualScriptConstant::get_input_value_port_count() const{
+
+	return 0;
+}
+int VisualScriptConstant::get_output_value_port_count() const{
+
+	return 1;
+}
+
+String VisualScriptConstant::get_output_sequence_port_text(int p_port) const {
+
+	return String();
+}
+
+PropertyInfo VisualScriptConstant::get_input_value_port_info(int p_idx) const{
+
+	return PropertyInfo();
+}
+
+PropertyInfo VisualScriptConstant::get_output_value_port_info(int p_idx) const{
+
+	PropertyInfo pinfo;
+	pinfo.name="get";
+	pinfo.type=type;
+	return pinfo;
+}
+
+
+String VisualScriptConstant::get_caption() const {
+
+	return "Constant";
+}
+
+String VisualScriptConstant::get_text() const {
+
+	return String(value);
+}
+
+void VisualScriptConstant::set_constant_type(Variant::Type p_type) {
+
+	if (type==p_type)
+		return;
+
+	type=p_type;
+	emit_signal("ports_changed");
+	Variant::CallError ce;
+	value=Variant::construct(type,NULL,0,ce);
+	_change_notify();
+
+}
+
+Variant::Type VisualScriptConstant::get_constant_type() const{
+
+	return type;
+}
+
+void VisualScriptConstant::set_constant_value(Variant p_value){
+
+	if (value==p_value)
+		return;
+
+	value=p_value;
+	emit_signal("ports_changed");
+}
+Variant VisualScriptConstant::get_constant_value() const{
+
+	return value;
+}
+
+void VisualScriptConstant::_validate_property(PropertyInfo& property) const {
+
+
+	if (property.name=="constant/value") {
+		property.type=type;
+		if (type==Variant::NIL)
+			property.usage=0; //do not save if nil
+	}
+}
+
+void VisualScriptConstant::_bind_methods() {
+
+	ObjectTypeDB::bind_method(_MD("set_constant_type","type"),&VisualScriptConstant::set_constant_type);
+	ObjectTypeDB::bind_method(_MD("get_constant_type"),&VisualScriptConstant::get_constant_type);
+
+	ObjectTypeDB::bind_method(_MD("set_constant_value","value"),&VisualScriptConstant::set_constant_value);
+	ObjectTypeDB::bind_method(_MD("get_constant_value"),&VisualScriptConstant::get_constant_value);
+
+	String argt="Null";
+	for(int i=1;i<Variant::VARIANT_MAX;i++) {
+		argt+=","+Variant::get_type_name(Variant::Type(i));
+	}
+
+
+	ADD_PROPERTY(PropertyInfo(Variant::INT,"constant/type",PROPERTY_HINT_ENUM,argt),_SCS("set_constant_type"),_SCS("get_constant_type"));
+	ADD_PROPERTY(PropertyInfo(Variant::NIL,"constant/value"),_SCS("set_constant_value"),_SCS("get_constant_value"));
+
+}
+
+VisualScriptNodeInstance* VisualScriptConstant::instance(VScriptInstance* p_instance) {
+
+	return NULL;
+}
+
+VisualScriptConstant::VisualScriptConstant() {
+
+	type=Variant::NIL;
+
+}
+
+
+
+//////////////////////////////////////////
+////////////////INDEX////////////////////
+//////////////////////////////////////////
+
+int VisualScriptIndexGet::get_output_sequence_port_count() const {
+
+	return 1;
+}
+
+bool VisualScriptIndexGet::has_input_sequence_port() const{
+
+	return true;
+}
+
+int VisualScriptIndexGet::get_input_value_port_count() const{
+
+	return 2;
+}
+int VisualScriptIndexGet::get_output_value_port_count() const{
+
+	return 1;
+}
+
+String VisualScriptIndexGet::get_output_sequence_port_text(int p_port) const {
+
+	return String();
+}
+
+PropertyInfo VisualScriptIndexGet::get_input_value_port_info(int p_idx) const{
+
+	if (p_idx==0) {
+		return PropertyInfo(Variant::NIL,"base");
+	} else {
+		return PropertyInfo(Variant::NIL,"index");
+
+	}
+}
+
+PropertyInfo VisualScriptIndexGet::get_output_value_port_info(int p_idx) const{
+
+	return PropertyInfo();
+}
+
+
+String VisualScriptIndexGet::get_caption() const {
+
+	return "IndexGet";
+}
+
+String VisualScriptIndexGet::get_text() const {
+
+	return String("get");
+}
+
+
+VisualScriptNodeInstance* VisualScriptIndexGet::instance(VScriptInstance* p_instance) {
+
+	return NULL;
+}
+
+VisualScriptIndexGet::VisualScriptIndexGet() {
+
+
+
+}
+
+//////////////////////////////////////////
+////////////////INDEXSET//////////////////
+//////////////////////////////////////////
+
+int VisualScriptIndexSet::get_output_sequence_port_count() const {
+
+	return 1;
+}
+
+bool VisualScriptIndexSet::has_input_sequence_port() const{
+
+	return true;
+}
+
+int VisualScriptIndexSet::get_input_value_port_count() const{
+
+	return 3;
+}
+int VisualScriptIndexSet::get_output_value_port_count() const{
+
+	return 0;
+}
+
+String VisualScriptIndexSet::get_output_sequence_port_text(int p_port) const {
+
+	return String();
+}
+
+PropertyInfo VisualScriptIndexSet::get_input_value_port_info(int p_idx) const{
+
+	if (p_idx==0) {
+		return PropertyInfo(Variant::NIL,"base");
+	} else if (p_idx==1){
+		return PropertyInfo(Variant::NIL,"index");
+
+	} else {
+		return PropertyInfo(Variant::NIL,"value");
+
+	}
+}
+
+PropertyInfo VisualScriptIndexSet::get_output_value_port_info(int p_idx) const{
+
+	return PropertyInfo();
+}
+
+
+String VisualScriptIndexSet::get_caption() const {
+
+	return "IndexSet";
+}
+
+String VisualScriptIndexSet::get_text() const {
+
+	return String("set");
+}
+
+
+VisualScriptNodeInstance* VisualScriptIndexSet::instance(VScriptInstance* p_instance) {
+
+	return NULL;
+}
+
+VisualScriptIndexSet::VisualScriptIndexSet() {
+
+
+
+}
+
+
+//////////////////////////////////////////
+////////////////GLOBALCONSTANT///////////
+//////////////////////////////////////////
+
+int VisualScriptGlobalConstant::get_output_sequence_port_count() const {
+
+	return 0;
+}
+
+bool VisualScriptGlobalConstant::has_input_sequence_port() const{
+
+	return false;
+}
+
+int VisualScriptGlobalConstant::get_input_value_port_count() const{
+
+	return 0;
+}
+int VisualScriptGlobalConstant::get_output_value_port_count() const{
+
+	return 1;
+}
+
+String VisualScriptGlobalConstant::get_output_sequence_port_text(int p_port) const {
+
+	return String();
+}
+
+PropertyInfo VisualScriptGlobalConstant::get_input_value_port_info(int p_idx) const{
+
+	return PropertyInfo();
+}
+
+PropertyInfo VisualScriptGlobalConstant::get_output_value_port_info(int p_idx) const{
+
+	return PropertyInfo(Variant::INT,"value");
+}
+
+
+String VisualScriptGlobalConstant::get_caption() const {
+
+	return "GlobalConst";
+}
+
+String VisualScriptGlobalConstant::get_text() const {
+
+	return GlobalConstants::get_global_constant_name(index);
+}
+
+void VisualScriptGlobalConstant::set_global_constant(int p_which) {
+
+	index=p_which;
+	_change_notify();
+	emit_signal("ports_changed");
+}
+
+int VisualScriptGlobalConstant::get_global_constant() {
+	return index;
+}
+
+
+
+VisualScriptNodeInstance* VisualScriptGlobalConstant::instance(VScriptInstance* p_instance) {
+
+	return NULL;
+}
+
+void VisualScriptGlobalConstant::_bind_methods() {
+
+	ObjectTypeDB::bind_method(_MD("set_global_constant","index"),&VisualScriptGlobalConstant::set_global_constant);
+	ObjectTypeDB::bind_method(_MD("get_global_constant"),&VisualScriptGlobalConstant::get_global_constant);
+
+	String cc;
+
+	for(int i=0;i<GlobalConstants::get_global_constant_count();i++) {
+
+		if (i>0)
+			cc+=",";
+		cc+=GlobalConstants::get_global_constant_name(i);
+	}
+	ADD_PROPERTY(PropertyInfo(Variant::INT,"constant",PROPERTY_HINT_ENUM,cc),_SCS("set_global_constant"),_SCS("get_global_constant"));
+}
+
+VisualScriptGlobalConstant::VisualScriptGlobalConstant() {
+
+	index=0;
+}
+
+
+
+//////////////////////////////////////////
+////////////////MATHCONSTANT///////////
+//////////////////////////////////////////
+
+
+const char* VisualScriptMathConstant::const_name[MATH_CONSTANT_MAX]={
+	"One",
+	"PI",
+	"PIx2",
+	"PI/2",
+	"E",
+	"Sqrt2",
+};
+int VisualScriptMathConstant::get_output_sequence_port_count() const {
+
+	return 0;
+}
+
+bool VisualScriptMathConstant::has_input_sequence_port() const{
+
+	return false;
+}
+
+int VisualScriptMathConstant::get_input_value_port_count() const{
+
+	return 0;
+}
+int VisualScriptMathConstant::get_output_value_port_count() const{
+
+	return 1;
+}
+
+String VisualScriptMathConstant::get_output_sequence_port_text(int p_port) const {
+
+	return String();
+}
+
+PropertyInfo VisualScriptMathConstant::get_input_value_port_info(int p_idx) const{
+
+	return PropertyInfo();
+}
+
+PropertyInfo VisualScriptMathConstant::get_output_value_port_info(int p_idx) const{
+
+	return PropertyInfo(Variant::INT,"value");
+}
+
+
+String VisualScriptMathConstant::get_caption() const {
+
+	return "MathConst";
+}
+
+String VisualScriptMathConstant::get_text() const {
+
+	return const_name[constant];
+}
+
+void VisualScriptMathConstant::set_math_constant(MathConstant p_which) {
+
+	constant=p_which;
+	_change_notify();
+	emit_signal("ports_changed");
+}
+
+VisualScriptMathConstant::MathConstant VisualScriptMathConstant::get_math_constant() {
+	return constant;
+}
+
+
+
+VisualScriptNodeInstance* VisualScriptMathConstant::instance(VScriptInstance* p_instance) {
+
+	return NULL;
+}
+
+void VisualScriptMathConstant::_bind_methods() {
+
+	ObjectTypeDB::bind_method(_MD("set_math_constant","which"),&VisualScriptMathConstant::set_math_constant);
+	ObjectTypeDB::bind_method(_MD("get_math_constant"),&VisualScriptMathConstant::get_math_constant);
+
+	String cc;
+
+	for(int i=0;i<MATH_CONSTANT_MAX;i++) {
+
+		if (i>0)
+			cc+=",";
+		cc+=const_name[i];
+	}
+	ADD_PROPERTY(PropertyInfo(Variant::INT,"constant",PROPERTY_HINT_ENUM,cc),_SCS("set_math_constant"),_SCS("get_math_constant"));
+}
+
+VisualScriptMathConstant::VisualScriptMathConstant() {
+
+	constant=MATH_CONSTANT_ONE;
+}
+
+
+
+//////////////////////////////////////////
+////////////////GLOBALSINGLETON///////////
+//////////////////////////////////////////
+
+int VisualScriptSingleton::get_output_sequence_port_count() const {
+
+	return 0;
+}
+
+bool VisualScriptSingleton::has_input_sequence_port() const{
+
+	return false;
+}
+
+int VisualScriptSingleton::get_input_value_port_count() const{
+
+	return 0;
+}
+int VisualScriptSingleton::get_output_value_port_count() const{
+
+	return 1;
+}
+
+String VisualScriptSingleton::get_output_sequence_port_text(int p_port) const {
+
+	return String();
+}
+
+PropertyInfo VisualScriptSingleton::get_input_value_port_info(int p_idx) const{
+
+	return PropertyInfo();
+}
+
+PropertyInfo VisualScriptSingleton::get_output_value_port_info(int p_idx) const{
+
+	return PropertyInfo(Variant::OBJECT,"instance");
+}
+
+
+String VisualScriptSingleton::get_caption() const {
+
+	return "Singleton";
+}
+
+String VisualScriptSingleton::get_text() const {
+
+	return singleton;
+}
+
+void VisualScriptSingleton::set_singleton(const String& p_string) {
+
+	singleton=p_string;
+
+	_change_notify();
+	emit_signal("ports_changed");
+}
+
+String VisualScriptSingleton::get_singleton() {
+	return singleton;
+}
+
+
+
+VisualScriptNodeInstance* VisualScriptSingleton::instance(VScriptInstance* p_instance) {
+
+	return NULL;
+}
+
+void VisualScriptSingleton::_bind_methods() {
+
+	ObjectTypeDB::bind_method(_MD("set_singleton","name"),&VisualScriptSingleton::set_singleton);
+	ObjectTypeDB::bind_method(_MD("get_singleton"),&VisualScriptSingleton::get_singleton);
+
+	String cc;
+
+	List<Globals::Singleton> singletons;
+
+	Globals::get_singleton()->get_singletons(&singletons);
+
+	for (List<Globals::Singleton>::Element *E=singletons.front();E;E=E->next()) {
+		if (E->get().name=="VS" || E->get().name=="PS" || E->get().name=="PS2D" || E->get().name=="AS" || E->get().name=="TS" || E->get().name=="SS" || E->get().name=="SS2D")
+			continue; //skip these, too simple named
+
+		if (cc!=String())
+			cc+=",";
+		cc+=E->get().name;
+	}
+
+	ADD_PROPERTY(PropertyInfo(Variant::STRING,"constant",PROPERTY_HINT_ENUM,cc),_SCS("set_singleton"),_SCS("get_singleton"));
+}
+
+VisualScriptSingleton::VisualScriptSingleton() {
+
+	singleton=String();
+}
+
+
+
+//////////////////////////////////////////
+////////////////GETNODE///////////
+//////////////////////////////////////////
+
+int VisualScriptSceneNode::get_output_sequence_port_count() const {
+
+	return 0;
+}
+
+bool VisualScriptSceneNode::has_input_sequence_port() const{
+
+	return false;
+}
+
+int VisualScriptSceneNode::get_input_value_port_count() const{
+
+	return 0;
+}
+int VisualScriptSceneNode::get_output_value_port_count() const{
+
+	return 1;
+}
+
+String VisualScriptSceneNode::get_output_sequence_port_text(int p_port) const {
+
+	return String();
+}
+
+PropertyInfo VisualScriptSceneNode::get_input_value_port_info(int p_idx) const{
+
+	return PropertyInfo();
+}
+
+PropertyInfo VisualScriptSceneNode::get_output_value_port_info(int p_idx) const{
+
+	return PropertyInfo(Variant::OBJECT,"node");
+}
+
+
+String VisualScriptSceneNode::get_caption() const {
+
+	return "SceneNode";
+}
+
+String VisualScriptSceneNode::get_text() const {
+
+	return path.simplified();
+}
+
+void VisualScriptSceneNode::set_node_path(const NodePath& p_path) {
+
+	path=p_path;
+	_change_notify();
+	emit_signal("ports_changed");
+}
+
+NodePath VisualScriptSceneNode::get_node_path() {
+	return path;
+}
+
+
+
+VisualScriptNodeInstance* VisualScriptSceneNode::instance(VScriptInstance* p_instance) {
+
+	return NULL;
+}
+
+#ifdef TOOLS_ENABLED
+
+static Node* _find_script_node(Node* p_edited_scene,Node* p_current_node,const Ref<Script> &script) {
+
+	if (p_edited_scene!=p_current_node && p_current_node->get_owner()!=p_edited_scene)
+		return NULL;
+
+	Ref<Script> scr = p_current_node->get_script();
+
+	if (scr.is_valid() && scr==script)
+		return p_current_node;
+
+	for(int i=0;i<p_current_node->get_child_count();i++) {
+		Node *n = _find_script_node(p_edited_scene,p_current_node->get_child(i),script);
+		if (n)
+			return n;
+	}
+
+	return NULL;
+}
+
+#endif
+
+void VisualScriptSceneNode::_validate_property(PropertyInfo& property) const {
+
+#ifdef TOOLS_ENABLED
+	if (property.name=="node_path") {
+
+		Ref<Script> script = get_visual_script();
+		if (!script.is_valid())
+			return;
+
+		MainLoop * main_loop = OS::get_singleton()->get_main_loop();
+		if (!main_loop)
+			return;
+
+		SceneTree *scene_tree = main_loop->cast_to<SceneTree>();
+
+		if (!scene_tree)
+			return;
+
+		Node *edited_scene = scene_tree->get_edited_scene_root();
+
+		if (!edited_scene)
+			return;
+
+		Node* script_node = _find_script_node(edited_scene,edited_scene,script);
+
+		if (!script_node)
+			return;
+
+		property.hint_string=script_node->get_path();
+	}
+#endif
+}
+
+void VisualScriptSceneNode::_bind_methods() {
+
+	ObjectTypeDB::bind_method(_MD("set_node_path","path"),&VisualScriptSceneNode::set_node_path);
+	ObjectTypeDB::bind_method(_MD("get_node_path"),&VisualScriptSceneNode::get_node_path);
+
+	ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_node_path"),_SCS("get_node_path"));
+}
+
+VisualScriptSceneNode::VisualScriptSceneNode() {
+
+	path=String(".");
+}
+
+
+void register_visual_script_nodes() {
+
+	VisualScriptLanguage::singleton->add_register_func("data/variable",create_node_generic<VisualScriptVariable>);
+	VisualScriptLanguage::singleton->add_register_func("data/constant",create_node_generic<VisualScriptConstant>);
+	VisualScriptLanguage::singleton->add_register_func("data/global_constant",create_node_generic<VisualScriptGlobalConstant>);
+	VisualScriptLanguage::singleton->add_register_func("data/math_constant",create_node_generic<VisualScriptMathConstant>);
+	VisualScriptLanguage::singleton->add_register_func("data/singleton",create_node_generic<VisualScriptSingleton>);
+	VisualScriptLanguage::singleton->add_register_func("data/scene_node",create_node_generic<VisualScriptSceneNode>);
+
+
+	VisualScriptLanguage::singleton->add_register_func("index/get",create_node_generic<VisualScriptIndexGet>);
+	VisualScriptLanguage::singleton->add_register_func("index/set",create_node_generic<VisualScriptIndexSet>);
+
+
+	VisualScriptLanguage::singleton->add_register_func("operators/compare/equal",create_op_node<Variant::OP_EQUAL>);
+	VisualScriptLanguage::singleton->add_register_func("operators/compare/not_equal",create_op_node<Variant::OP_NOT_EQUAL>);
+	VisualScriptLanguage::singleton->add_register_func("operators/compare/less",create_op_node<Variant::OP_LESS>);
+	VisualScriptLanguage::singleton->add_register_func("operators/compare/less_equal",create_op_node<Variant::OP_LESS_EQUAL>);
+	VisualScriptLanguage::singleton->add_register_func("operators/compare/greater",create_op_node<Variant::OP_GREATER>);
+	VisualScriptLanguage::singleton->add_register_func("operators/compare/greater_equal",create_op_node<Variant::OP_GREATER_EQUAL>);
+	//mathematic
+	VisualScriptLanguage::singleton->add_register_func("operators/math/add",create_op_node<Variant::OP_ADD>);
+	VisualScriptLanguage::singleton->add_register_func("operators/math/subtract",create_op_node<Variant::OP_SUBSTRACT>);
+	VisualScriptLanguage::singleton->add_register_func("operators/math/multiply",create_op_node<Variant::OP_MULTIPLY>);
+	VisualScriptLanguage::singleton->add_register_func("operators/math/divide",create_op_node<Variant::OP_DIVIDE>);
+	VisualScriptLanguage::singleton->add_register_func("operators/math/negate",create_op_node<Variant::OP_NEGATE>);
+	VisualScriptLanguage::singleton->add_register_func("operators/math/remainder",create_op_node<Variant::OP_MODULE>);
+	VisualScriptLanguage::singleton->add_register_func("operators/math/string_concat",create_op_node<Variant::OP_STRING_CONCAT>);
+	//bitwise
+	VisualScriptLanguage::singleton->add_register_func("operators/bitwise/shift_left",create_op_node<Variant::OP_SHIFT_LEFT>);
+	VisualScriptLanguage::singleton->add_register_func("operators/bitwise/shift_right",create_op_node<Variant::OP_SHIFT_RIGHT>);
+	VisualScriptLanguage::singleton->add_register_func("operators/bitwise/bit_and",create_op_node<Variant::OP_BIT_AND>);
+	VisualScriptLanguage::singleton->add_register_func("operators/bitwise/bit_or",create_op_node<Variant::OP_BIT_OR>);
+	VisualScriptLanguage::singleton->add_register_func("operators/bitwise/bit_xor",create_op_node<Variant::OP_BIT_XOR>);
+	VisualScriptLanguage::singleton->add_register_func("operators/bitwise/bit_negate",create_op_node<Variant::OP_BIT_NEGATE>);
+	//logic
+	VisualScriptLanguage::singleton->add_register_func("operators/logic/and",create_op_node<Variant::OP_AND>);
+	VisualScriptLanguage::singleton->add_register_func("operators/logic/or",create_op_node<Variant::OP_OR>);
+	VisualScriptLanguage::singleton->add_register_func("operators/logic/xor",create_op_node<Variant::OP_XOR>);
+	VisualScriptLanguage::singleton->add_register_func("operators/logic/not",create_op_node<Variant::OP_NOT>);
+	VisualScriptLanguage::singleton->add_register_func("operators/logic/in",create_op_node<Variant::OP_IN>);
+
+}

+ 394 - 0
modules/visual_script/visual_script_nodes.h

@@ -0,0 +1,394 @@
+#ifndef VISUAL_SCRIPT_NODES_H
+#define VISUAL_SCRIPT_NODES_H
+
+#include "visual_script.h"
+
+class VisualScriptFunction : public VisualScriptNode {
+
+	OBJ_TYPE(VisualScriptFunction,VisualScriptNode)
+
+
+	struct Argument {
+		String name;
+		Variant::Type type;
+	};
+
+	Vector<Argument> arguments;
+protected:
+
+	bool _set(const StringName& p_name, const Variant& p_value);
+	bool _get(const StringName& p_name,Variant &r_ret) const;
+	void _get_property_list( List<PropertyInfo> *p_list) const;
+
+public:
+
+	virtual int get_output_sequence_port_count() const;
+	virtual bool has_input_sequence_port() const;
+
+
+	virtual String get_output_sequence_port_text(int p_port) const;
+
+
+	virtual int get_input_value_port_count() const;
+	virtual int get_output_value_port_count() const;
+
+
+	virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+	virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+	virtual String get_caption() const;
+	virtual String get_text() const;
+
+	void add_argument(Variant::Type p_type,const String& p_name,int p_index=-1);
+	void set_argument_type(int p_argidx,Variant::Type p_type);
+	Variant::Type get_argument_type(int p_argidx) const;
+	void set_argument_name(int p_argidx,const String& p_name);
+	String get_argument_name(int p_argidx) const;
+	void remove_argument(int p_argidx);
+	int get_argument_count() const;
+
+	virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance);
+
+	VisualScriptFunction();
+};
+
+
+class VisualScriptOperator : public VisualScriptNode {
+
+	OBJ_TYPE(VisualScriptOperator,VisualScriptNode)
+
+
+	Variant::Operator op;
+protected:
+
+	static void _bind_methods();
+public:
+
+	virtual int get_output_sequence_port_count() const;
+	virtual bool has_input_sequence_port() const;
+
+
+	virtual String get_output_sequence_port_text(int p_port) const;
+
+
+	virtual int get_input_value_port_count() const;
+	virtual int get_output_value_port_count() const;
+
+
+	virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+	virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+	virtual String get_caption() const;
+	virtual String get_text() const;
+
+	void set_operator(Variant::Operator p_op);
+	Variant::Operator get_operator() const;
+
+	virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance);
+
+	VisualScriptOperator();
+};
+
+
+class VisualScriptVariable : public VisualScriptNode {
+
+	OBJ_TYPE(VisualScriptVariable,VisualScriptNode)
+
+
+	StringName variable;
+protected:
+
+	virtual void _validate_property(PropertyInfo& property) const;
+	static void _bind_methods();
+public:
+
+	virtual int get_output_sequence_port_count() const;
+	virtual bool has_input_sequence_port() const;
+
+
+	virtual String get_output_sequence_port_text(int p_port) const;
+
+
+	virtual int get_input_value_port_count() const;
+	virtual int get_output_value_port_count() const;
+
+
+	virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+	virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+	virtual String get_caption() const;
+	virtual String get_text() const;
+
+	void set_variable(StringName p_var);
+	StringName get_variable() const;
+
+	virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance);
+
+	VisualScriptVariable();
+};
+
+class VisualScriptConstant : public VisualScriptNode {
+
+	OBJ_TYPE(VisualScriptConstant,VisualScriptNode)
+
+
+	Variant::Type type;
+	Variant value;
+protected:
+	virtual void _validate_property(PropertyInfo& property) const;
+	static void _bind_methods();
+
+public:
+
+	virtual int get_output_sequence_port_count() const;
+	virtual bool has_input_sequence_port() const;
+
+
+	virtual String get_output_sequence_port_text(int p_port) const;
+
+
+	virtual int get_input_value_port_count() const;
+	virtual int get_output_value_port_count() const;
+
+
+	virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+	virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+	virtual String get_caption() const;
+	virtual String get_text() const;
+
+	void set_constant_type(Variant::Type p_type);
+	Variant::Type get_constant_type() const;
+
+	void set_constant_value(Variant p_value);
+	Variant get_constant_value() const;
+
+	virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance);
+
+	VisualScriptConstant();
+};
+
+
+class VisualScriptIndexGet : public VisualScriptNode {
+
+	OBJ_TYPE(VisualScriptIndexGet,VisualScriptNode)
+
+
+public:
+
+	virtual int get_output_sequence_port_count() const;
+	virtual bool has_input_sequence_port() const;
+
+
+	virtual String get_output_sequence_port_text(int p_port) const;
+
+
+	virtual int get_input_value_port_count() const;
+	virtual int get_output_value_port_count() const;
+
+
+	virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+	virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+	virtual String get_caption() const;
+	virtual String get_text() const;
+
+	virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance);
+
+	VisualScriptIndexGet();
+};
+
+
+class VisualScriptIndexSet : public VisualScriptNode {
+
+	OBJ_TYPE(VisualScriptIndexSet,VisualScriptNode)
+
+
+public:
+
+	virtual int get_output_sequence_port_count() const;
+	virtual bool has_input_sequence_port() const;
+
+
+	virtual String get_output_sequence_port_text(int p_port) const;
+
+
+	virtual int get_input_value_port_count() const;
+	virtual int get_output_value_port_count() const;
+
+
+	virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+	virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+	virtual String get_caption() const;
+	virtual String get_text() const;
+
+	virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance);
+
+	VisualScriptIndexSet();
+};
+
+
+
+class VisualScriptGlobalConstant : public VisualScriptNode {
+
+	OBJ_TYPE(VisualScriptGlobalConstant,VisualScriptNode)
+
+	int index;
+
+	static void _bind_methods();
+public:
+
+	virtual int get_output_sequence_port_count() const;
+	virtual bool has_input_sequence_port() const;
+
+
+	virtual String get_output_sequence_port_text(int p_port) const;
+
+
+	virtual int get_input_value_port_count() const;
+	virtual int get_output_value_port_count() const;
+
+
+	virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+	virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+	virtual String get_caption() const;
+	virtual String get_text() const;
+
+	void set_global_constant(int p_which);
+	int get_global_constant();
+
+	virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance);
+
+	VisualScriptGlobalConstant();
+};
+
+
+
+class VisualScriptMathConstant : public VisualScriptNode {
+
+	OBJ_TYPE(VisualScriptMathConstant,VisualScriptNode)
+public:
+
+	enum MathConstant {
+		MATH_CONSTANT_ONE,
+		MATH_CONSTANT_PI,
+		MATH_CONSTANT_2PI,
+		MATH_CONSTANT_HALF_PI,
+		MATH_CONSTANT_E,
+		MATH_CONSTANT_SQRT2,
+		MATH_CONSTANT_MAX,
+	};
+
+private:
+	static const char* const_name[MATH_CONSTANT_MAX];
+	MathConstant constant;
+protected:
+	static void _bind_methods();
+public:
+
+	virtual int get_output_sequence_port_count() const;
+	virtual bool has_input_sequence_port() const;
+
+
+	virtual String get_output_sequence_port_text(int p_port) const;
+
+
+	virtual int get_input_value_port_count() const;
+	virtual int get_output_value_port_count() const;
+
+
+	virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+	virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+	virtual String get_caption() const;
+	virtual String get_text() const;
+
+	void set_math_constant(MathConstant p_which);
+	MathConstant get_math_constant();
+
+	virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance);
+
+	VisualScriptMathConstant();
+};
+
+VARIANT_ENUM_CAST( VisualScriptMathConstant::MathConstant )
+
+class VisualScriptSingleton : public VisualScriptNode {
+
+	OBJ_TYPE(VisualScriptSingleton,VisualScriptNode)
+
+	String singleton;
+
+	static void _bind_methods();
+public:
+
+	virtual int get_output_sequence_port_count() const;
+	virtual bool has_input_sequence_port() const;
+
+
+	virtual String get_output_sequence_port_text(int p_port) const;
+
+
+	virtual int get_input_value_port_count() const;
+	virtual int get_output_value_port_count() const;
+
+
+	virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+	virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+	virtual String get_caption() const;
+	virtual String get_text() const;
+
+	void set_singleton(const String &p_string);
+	String get_singleton();
+
+	virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance);
+
+	VisualScriptSingleton();
+};
+
+
+
+
+class VisualScriptSceneNode : public VisualScriptNode {
+
+	OBJ_TYPE(VisualScriptSceneNode,VisualScriptNode)
+
+	NodePath path;
+protected:
+	virtual void _validate_property(PropertyInfo& property) const;
+	static void _bind_methods();
+public:
+
+	virtual int get_output_sequence_port_count() const;
+	virtual bool has_input_sequence_port() const;
+
+
+	virtual String get_output_sequence_port_text(int p_port) const;
+
+
+	virtual int get_input_value_port_count() const;
+	virtual int get_output_value_port_count() const;
+
+
+	virtual PropertyInfo get_input_value_port_info(int p_idx) const;
+	virtual PropertyInfo get_output_value_port_info(int p_idx) const;
+
+	virtual String get_caption() const;
+	virtual String get_text() const;
+
+	void set_node_path(const NodePath &p_path);
+	NodePath get_node_path();
+
+	virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance);
+
+	VisualScriptSceneNode();
+};
+
+
+
+void register_visual_script_nodes();
+
+#endif // VISUAL_SCRIPT_NODES_H

+ 106 - 7
scene/gui/graph_edit.cpp

@@ -178,6 +178,7 @@ void GraphEdit::_graph_node_raised(Node* p_gn) {
 	ERR_FAIL_COND(!gn);
 	ERR_FAIL_COND(!gn);
 	gn->raise();
 	gn->raise();
 	top_layer->raise();
 	top_layer->raise();
+	emit_signal("node_selected",p_gn);
 
 
 }
 }
 
 
@@ -295,6 +296,36 @@ void GraphEdit::_top_layer_input(const InputEvent& p_ev) {
 				Vector2 pos = gn->get_connection_output_pos(j)+gn->get_pos();
 				Vector2 pos = gn->get_connection_output_pos(j)+gn->get_pos();
 				if (pos.distance_to(mpos)<grab_r) {
 				if (pos.distance_to(mpos)<grab_r) {
 
 
+
+					if (valid_left_disconnect_types.has(gn->get_connection_output_type(j))) {
+						//check disconnect
+						for (List<Connection>::Element*E=connections.front();E;E=E->next()) {
+
+							if (E->get().from==gn->get_name() && E->get().from_port==j) {
+
+								Node*to = get_node(String(E->get().to));
+								if (to && to->cast_to<GraphNode>()) {
+
+									connecting_from=E->get().to;
+									connecting_index=E->get().to_port;
+									connecting_out=false;
+									connecting_type=to->cast_to<GraphNode>()->get_connection_input_type(E->get().to_port);
+									connecting_color=to->cast_to<GraphNode>()->get_connection_input_color(E->get().to_port);
+									connecting_target=false;
+									connecting_to=pos;
+
+									emit_signal("disconnection_request",E->get().from,E->get().from_port,E->get().to,E->get().to_port);
+									to = get_node(String(connecting_from)); //maybe it was erased
+									if (to && to->cast_to<GraphNode>()) {
+										connecting=true;
+									}
+									return;
+								}
+
+							}
+						}
+					}
+
 					connecting=true;
 					connecting=true;
 					connecting_from=gn->get_name();
 					connecting_from=gn->get_name();
 					connecting_index=j;
 					connecting_index=j;
@@ -315,7 +346,7 @@ void GraphEdit::_top_layer_input(const InputEvent& p_ev) {
 
 
 				if (pos.distance_to(mpos)<grab_r) {
 				if (pos.distance_to(mpos)<grab_r) {
 
 
-					if (right_disconnects) {
+					if (right_disconnects || valid_right_disconnect_types.has(gn->get_connection_input_type(j))) {
 						//check disconnect
 						//check disconnect
 						for (List<Connection>::Element*E=connections.front();E;E=E->next()) {
 						for (List<Connection>::Element*E=connections.front();E;E=E->next()) {
 
 
@@ -381,7 +412,7 @@ void GraphEdit::_top_layer_input(const InputEvent& p_ev) {
 
 
 					Vector2 pos = gn->get_connection_output_pos(j)+gn->get_pos();
 					Vector2 pos = gn->get_connection_output_pos(j)+gn->get_pos();
 					int type =gn->get_connection_output_type(j);
 					int type =gn->get_connection_output_type(j);
-					if (type==connecting_type && pos.distance_to(mpos)<grab_r) {
+					if ((type==connecting_type ||valid_connection_types.has(ConnType(type,connecting_type))) && pos.distance_to(mpos)<grab_r) {
 
 
 						connecting_target=true;
 						connecting_target=true;
 						connecting_to=pos;
 						connecting_to=pos;
@@ -398,7 +429,7 @@ void GraphEdit::_top_layer_input(const InputEvent& p_ev) {
 
 
 					Vector2 pos = gn->get_connection_input_pos(j)+gn->get_pos();
 					Vector2 pos = gn->get_connection_input_pos(j)+gn->get_pos();
 					int type =gn->get_connection_input_type(j);
 					int type =gn->get_connection_input_type(j);
-					if (type==connecting_type && pos.distance_to(mpos)<grab_r) {
+					if ((type==connecting_type ||valid_connection_types.has(ConnType(type,connecting_type))) && pos.distance_to(mpos)<grab_r) {
 						connecting_target=true;
 						connecting_target=true;
 						connecting_to=pos;
 						connecting_to=pos;
 						connecting_target_to=gn->get_name();
 						connecting_target_to=gn->get_name();
@@ -433,7 +464,7 @@ void GraphEdit::_top_layer_input(const InputEvent& p_ev) {
 
 
 }
 }
 
 
-void GraphEdit::_draw_cos_line(const Vector2& p_from, const Vector2& p_to,const Color& p_color) {
+void GraphEdit::_draw_cos_line(const Vector2& p_from, const Vector2& p_to,const Color& p_color,const Color& p_to_color) {
 
 
 	static const int steps = 20;
 	static const int steps = 20;
 
 
@@ -454,7 +485,7 @@ void GraphEdit::_draw_cos_line(const Vector2& p_from, const Vector2& p_to,const
 
 
 		if (i>0) {
 		if (i>0) {
 
 
-			top_layer->draw_line(prev,p,p_color,2);
+			top_layer->draw_line(prev,p,p_color.linear_interpolate(p_to_color,d),2);
 		}
 		}
 
 
 		prev=p;
 		prev=p;
@@ -488,7 +519,7 @@ void GraphEdit::_top_layer_draw() {
 			col.g+=0.4;
 			col.g+=0.4;
 			col.b+=0.4;
 			col.b+=0.4;
 		}
 		}
-		_draw_cos_line(pos,topos,col);
+		_draw_cos_line(pos,topos,col,col);
 	}
 	}
 
 
 	List<List<Connection>::Element* > to_erase;
 	List<List<Connection>::Element* > to_erase;
@@ -526,7 +557,8 @@ void GraphEdit::_top_layer_draw() {
 		Vector2 frompos=gfrom->get_connection_output_pos(E->get().from_port)+gfrom->get_pos();
 		Vector2 frompos=gfrom->get_connection_output_pos(E->get().from_port)+gfrom->get_pos();
 		Color color = gfrom->get_connection_output_color(E->get().from_port);
 		Color color = gfrom->get_connection_output_color(E->get().from_port);
 		Vector2 topos=gto->get_connection_input_pos(E->get().to_port)+gto->get_pos();
 		Vector2 topos=gto->get_connection_input_pos(E->get().to_port)+gto->get_pos();
-		_draw_cos_line(frompos,topos,color);
+		Color tocolor = gto->get_connection_input_color(E->get().to_port);
+		_draw_cos_line(frompos,topos,color,tocolor);
 
 
 	}
 	}
 
 
@@ -538,6 +570,18 @@ void GraphEdit::_top_layer_draw() {
 		top_layer->draw_rect(box_selecting_rect,Color(0.7,0.7,1.0,0.3));
 		top_layer->draw_rect(box_selecting_rect,Color(0.7,0.7,1.0,0.3));
 }
 }
 
 
+void GraphEdit::set_selected(Node* p_child) {
+
+	for(int i=get_child_count()-1;i>=0;i--) {
+
+		GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+		if (!gn)
+			continue;
+
+		gn->set_selected(gn==p_child);
+	}
+}
+
 void GraphEdit::_input_event(const InputEvent& p_ev) {
 void GraphEdit::_input_event(const InputEvent& p_ev) {
 
 
 	if (p_ev.type==InputEvent::MOUSE_MOTION && (p_ev.mouse_motion.button_mask&BUTTON_MASK_MIDDLE || (p_ev.mouse_motion.button_mask&BUTTON_MASK_LEFT && Input::get_singleton()->is_key_pressed(KEY_SPACE)))) {
 	if (p_ev.type==InputEvent::MOUSE_MOTION && (p_ev.mouse_motion.button_mask&BUTTON_MASK_MIDDLE || (p_ev.mouse_motion.button_mask&BUTTON_MASK_LEFT && Input::get_singleton()->is_key_pressed(KEY_SPACE)))) {
@@ -804,6 +848,29 @@ bool GraphEdit::is_right_disconnects_enabled() const{
 	return right_disconnects;
 	return right_disconnects;
 }
 }
 
 
+void GraphEdit::add_valid_right_disconnect_type(int p_type) {
+
+	valid_right_disconnect_types.insert(p_type);
+}
+
+void GraphEdit::remove_valid_right_disconnect_type(int p_type){
+
+	valid_right_disconnect_types.erase(p_type);
+
+}
+
+void GraphEdit::add_valid_left_disconnect_type(int p_type){
+
+	valid_left_disconnect_types.insert(p_type);
+
+}
+
+void GraphEdit::remove_valid_left_disconnect_type(int p_type){
+
+	valid_left_disconnect_types.erase(p_type);
+
+}
+
 Array GraphEdit::_get_connection_list() const {
 Array GraphEdit::_get_connection_list() const {
 
 
 	List<Connection> conns;
 	List<Connection> conns;
@@ -838,6 +905,35 @@ void GraphEdit::_zoom_plus() {
 	set_zoom(zoom*ZOOM_SCALE);
 	set_zoom(zoom*ZOOM_SCALE);
 }
 }
 
 
+void GraphEdit::add_valid_connection_type(int p_type,int p_with_type) {
+
+	ConnType ct;
+	ct.type_a=p_type;
+	ct.type_b=p_with_type;
+
+	valid_connection_types.insert(ct);
+}
+
+void GraphEdit::remove_valid_connection_type(int p_type,int p_with_type) {
+
+	ConnType ct;
+	ct.type_a=p_type;
+	ct.type_b=p_with_type;
+
+	valid_connection_types.erase(ct);
+
+}
+
+bool GraphEdit::is_valid_connection_type(int p_type,int p_with_type) const {
+
+	ConnType ct;
+	ct.type_a=p_type;
+	ct.type_b=p_with_type;
+
+	return valid_connection_types.has(ct);
+
+}
+
 
 
 void GraphEdit::_bind_methods() {
 void GraphEdit::_bind_methods() {
 
 
@@ -865,10 +961,13 @@ void GraphEdit::_bind_methods() {
 
 
 	ObjectTypeDB::bind_method(_MD("_input_event"),&GraphEdit::_input_event);
 	ObjectTypeDB::bind_method(_MD("_input_event"),&GraphEdit::_input_event);
 
 
+	ObjectTypeDB::bind_method(_MD("set_selected","node"),&GraphEdit::set_selected);
+
 	ADD_SIGNAL(MethodInfo("connection_request",PropertyInfo(Variant::STRING,"from"),PropertyInfo(Variant::INT,"from_slot"),PropertyInfo(Variant::STRING,"to"),PropertyInfo(Variant::INT,"to_slot")));
 	ADD_SIGNAL(MethodInfo("connection_request",PropertyInfo(Variant::STRING,"from"),PropertyInfo(Variant::INT,"from_slot"),PropertyInfo(Variant::STRING,"to"),PropertyInfo(Variant::INT,"to_slot")));
 	ADD_SIGNAL(MethodInfo("disconnection_request",PropertyInfo(Variant::STRING,"from"),PropertyInfo(Variant::INT,"from_slot"),PropertyInfo(Variant::STRING,"to"),PropertyInfo(Variant::INT,"to_slot")));
 	ADD_SIGNAL(MethodInfo("disconnection_request",PropertyInfo(Variant::STRING,"from"),PropertyInfo(Variant::INT,"from_slot"),PropertyInfo(Variant::STRING,"to"),PropertyInfo(Variant::INT,"to_slot")));
 	ADD_SIGNAL(MethodInfo("popup_request", PropertyInfo(Variant::VECTOR2,"p_position")));
 	ADD_SIGNAL(MethodInfo("popup_request", PropertyInfo(Variant::VECTOR2,"p_position")));
 	ADD_SIGNAL(MethodInfo("duplicate_nodes_request"));
 	ADD_SIGNAL(MethodInfo("duplicate_nodes_request"));
+	ADD_SIGNAL(MethodInfo("node_selected",PropertyInfo(Variant::OBJECT,"node")));
 	ADD_SIGNAL(MethodInfo("delete_nodes_request"));
 	ADD_SIGNAL(MethodInfo("delete_nodes_request"));
 	ADD_SIGNAL(MethodInfo("_begin_node_move"));
 	ADD_SIGNAL(MethodInfo("_begin_node_move"));
 	ADD_SIGNAL(MethodInfo("_end_node_move"));
 	ADD_SIGNAL(MethodInfo("_end_node_move"));

+ 37 - 1
scene/gui/graph_edit.h

@@ -106,7 +106,7 @@ private:
 	bool updating;
 	bool updating;
 	List<Connection> connections;
 	List<Connection> connections;
 
 
-	void _draw_cos_line(const Vector2& p_from, const Vector2& p_to,const Color& p_color);
+	void _draw_cos_line(const Vector2& p_from, const Vector2& p_to, const Color& p_color, const Color &p_to_color);
 
 
 	void _graph_node_raised(Node* p_gn);
 	void _graph_node_raised(Node* p_gn);
 	void _graph_node_moved(Node *p_gn);
 	void _graph_node_moved(Node *p_gn);
@@ -122,6 +122,30 @@ private:
 
 
 	Array _get_connection_list() const;
 	Array _get_connection_list() const;
 
 
+	struct ConnType {
+
+		union {
+			struct {
+				uint32_t type_a;
+				uint32_t type_b;
+			};
+			uint64_t key;
+		};
+
+		bool operator<(const ConnType& p_type) const {
+			return key<p_type.key;
+		}
+
+		ConnType(uint32_t a=0, uint32_t b=0) {
+			type_a=a;
+			type_b=b;
+		}
+	};
+
+	Set<ConnType> valid_connection_types;
+	Set<int> valid_left_disconnect_types;
+	Set<int> valid_right_disconnect_types;
+
 	friend class GraphEditFilter;
 	friend class GraphEditFilter;
 	bool _filter_input(const Point2& p_point);
 	bool _filter_input(const Point2& p_point);
 protected:
 protected:
@@ -138,6 +162,10 @@ public:
 	void disconnect_node(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port);
 	void disconnect_node(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port);
 	void clear_connections();
 	void clear_connections();
 
 
+	void add_valid_connection_type(int p_type,int p_with_type);
+	void remove_valid_connection_type(int p_type,int p_with_type);
+	bool is_valid_connection_type(int p_type,int p_with_type) const;
+
 	void set_zoom(float p_zoom);
 	void set_zoom(float p_zoom);
 	float get_zoom() const;
 	float get_zoom() const;
 
 
@@ -147,8 +175,16 @@ public:
 	void set_right_disconnects(bool p_enable);
 	void set_right_disconnects(bool p_enable);
 	bool is_right_disconnects_enabled() const;
 	bool is_right_disconnects_enabled() const;
 
 
+	void add_valid_right_disconnect_type(int p_type);
+	void remove_valid_right_disconnect_type(int p_type);
+
+	void add_valid_left_disconnect_type(int p_type);
+	void remove_valid_left_disconnect_type(int p_type);
+
 	Vector2 get_scroll_ofs() const;
 	Vector2 get_scroll_ofs() const;
 
 
+	void set_selected(Node* p_child);
+
 
 
 	GraphEdit();
 	GraphEdit();
 };
 };

+ 18 - 6
scene/gui/graph_node.cpp

@@ -223,10 +223,20 @@ void GraphNode::_notification(int p_what) {
 				continue;
 				continue;
 			const Slot &s=slot_info[E->key()];
 			const Slot &s=slot_info[E->key()];
 			//left
 			//left
-			if (s.enable_left)
-				port->draw(get_canvas_item(),icofs+Point2(edgeofs,cache_y[E->key()]),s.color_left);
-			if (s.enable_right)
-				port->draw(get_canvas_item(),icofs+Point2(get_size().x-edgeofs,cache_y[E->key()]),s.color_right);
+			if (s.enable_left) {
+				Ref<Texture> p = port;
+				if (s.custom_slot_left.is_valid()) {
+					p=s.custom_slot_left;
+				}
+				p->draw(get_canvas_item(),icofs+Point2(edgeofs,cache_y[E->key()]),s.color_left);
+			}
+			if (s.enable_right) {
+				Ref<Texture> p = port;
+				if (s.custom_slot_right.is_valid()) {
+					p=s.custom_slot_right;
+				}
+				p->draw(get_canvas_item(),icofs+Point2(get_size().x-edgeofs,cache_y[E->key()]),s.color_right);
+			}
 
 
 		}
 		}
 	}
 	}
@@ -239,7 +249,7 @@ void GraphNode::_notification(int p_what) {
 }
 }
 
 
 
 
-void GraphNode::set_slot(int p_idx,bool p_enable_left,int p_type_left,const Color& p_color_left, bool p_enable_right,int p_type_right,const Color& p_color_right) {
+void GraphNode::set_slot(int p_idx,bool p_enable_left,int p_type_left,const Color& p_color_left, bool p_enable_right,int p_type_right,const Color& p_color_right,const Ref<Texture>& p_custom_left,const Ref<Texture>& p_custom_right) {
 
 
 	ERR_FAIL_COND(p_idx<0);
 	ERR_FAIL_COND(p_idx<0);
 
 
@@ -255,6 +265,8 @@ void GraphNode::set_slot(int p_idx,bool p_enable_left,int p_type_left,const Colo
 	s.enable_right=p_enable_right;
 	s.enable_right=p_enable_right;
 	s.type_right=p_type_right;
 	s.type_right=p_type_right;
 	s.color_right=p_color_right;
 	s.color_right=p_color_right;
+	s.custom_slot_left=p_custom_left;
+	s.custom_slot_right=p_custom_right;
 	slot_info[p_idx]=s;
 	slot_info[p_idx]=s;
 	update();
 	update();
 	connpos_dirty=true;
 	connpos_dirty=true;
@@ -580,7 +592,7 @@ void GraphNode::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("get_title"),&GraphNode::get_title);
 	ObjectTypeDB::bind_method(_MD("get_title"),&GraphNode::get_title);
 	ObjectTypeDB::bind_method(_MD("_input_event"),&GraphNode::_input_event);
 	ObjectTypeDB::bind_method(_MD("_input_event"),&GraphNode::_input_event);
 
 
-	ObjectTypeDB::bind_method(_MD("set_slot","idx","enable_left","type_left","color_left","enable_right","type_right","color_right"),&GraphNode::set_slot);
+	ObjectTypeDB::bind_method(_MD("set_slot","idx","enable_left","type_left","color_left","enable_right","type_right","color_right","custom_left","custom_right"),&GraphNode::set_slot,DEFVAL(Ref<Texture>()),DEFVAL(Ref<Texture>()));
 	ObjectTypeDB::bind_method(_MD("clear_slot","idx"),&GraphNode::clear_slot);
 	ObjectTypeDB::bind_method(_MD("clear_slot","idx"),&GraphNode::clear_slot);
 	ObjectTypeDB::bind_method(_MD("clear_all_slots","idx"),&GraphNode::clear_all_slots);
 	ObjectTypeDB::bind_method(_MD("clear_all_slots","idx"),&GraphNode::clear_all_slots);
 	ObjectTypeDB::bind_method(_MD("is_slot_enabled_left","idx"),&GraphNode::is_slot_enabled_left);
 	ObjectTypeDB::bind_method(_MD("is_slot_enabled_left","idx"),&GraphNode::is_slot_enabled_left);

+ 3 - 1
scene/gui/graph_node.h

@@ -44,6 +44,8 @@ class GraphNode : public Container {
 		bool enable_right;
 		bool enable_right;
 		int type_right;
 		int type_right;
 		Color color_right;
 		Color color_right;
+		Ref<Texture> custom_slot_left;
+		Ref<Texture> custom_slot_right;
 
 
 
 
 		Slot() { enable_left=false; type_left=0; color_left=Color(1,1,1,1); enable_right=false; type_right=0; color_right=Color(1,1,1,1); }
 		Slot() { enable_left=false; type_left=0; color_left=Color(1,1,1,1); enable_right=false; type_right=0; color_right=Color(1,1,1,1); }
@@ -91,7 +93,7 @@ public:
 
 
 
 
 
 
-	void set_slot(int p_idx,bool p_enable_left,int p_type_left,const Color& p_color_left, bool p_enable_right,int p_type_right,const Color& p_color_right);
+	void set_slot(int p_idx,bool p_enable_left,int p_type_left,const Color& p_color_left, bool p_enable_right,int p_type_right,const Color& p_color_right,const Ref<Texture>& p_custom_left=Ref<Texture>(),const Ref<Texture>& p_custom_right=Ref<Texture>());
 	void clear_slot(int p_idx);
 	void clear_slot(int p_idx);
 	void clear_all_slots();
 	void clear_all_slots();
 	bool is_slot_enabled_left(int p_idx) const;
 	bool is_slot_enabled_left(int p_idx) const;

+ 3 - 3
scene/resources/default_theme/default_theme.cpp

@@ -626,8 +626,8 @@ void fill_default_theme(Ref<Theme>& t,const Ref<Font> & default_font,const Ref<F
 
 
 	// GraphNode
 	// GraphNode
 
 
-	Ref<StyleBoxTexture> graphsb = make_stylebox(graph_node_png,6,24,6,5,3,24,16,5);
-	Ref<StyleBoxTexture> graphsbselected = make_stylebox(graph_node_selected_png,6,24,6,5,3,24,16,5);
+	Ref<StyleBoxTexture> graphsb = make_stylebox(graph_node_png,6,24,6,5,16,24,16,5);
+	Ref<StyleBoxTexture> graphsbselected = make_stylebox(graph_node_selected_png,6,24,6,5,16,24,16,5);
 	Ref<StyleBoxTexture> graphsbdefault = make_stylebox(graph_node_default_png,4,4,4,4,6,4,4,4);
 	Ref<StyleBoxTexture> graphsbdefault = make_stylebox(graph_node_default_png,4,4,4,4,6,4,4,4);
 	Ref<StyleBoxTexture> graphsbdeffocus = make_stylebox(graph_node_default_focus_png,4,4,4,4,6,4,4,4);
 	Ref<StyleBoxTexture> graphsbdeffocus = make_stylebox(graph_node_default_focus_png,4,4,4,4,6,4,4,4);
 	//graphsb->set_expand_margin_size(MARGIN_LEFT,10);
 	//graphsb->set_expand_margin_size(MARGIN_LEFT,10);
@@ -641,7 +641,7 @@ void fill_default_theme(Ref<Theme>& t,const Ref<Font> & default_font,const Ref<F
 	t->set_icon("close","GraphNode", make_icon( graph_node_close_png ) );
 	t->set_icon("close","GraphNode", make_icon( graph_node_close_png ) );
 	t->set_font("title_font","GraphNode", default_font );
 	t->set_font("title_font","GraphNode", default_font );
 	t->set_color("title_color","GraphNode", Color(0,0,0,1));
 	t->set_color("title_color","GraphNode", Color(0,0,0,1));
-	t->set_constant("title_offset","GraphNode", 18 *scale);
+	t->set_constant("title_offset","GraphNode", 20 *scale);
 	t->set_constant("close_offset","GraphNode", 18 *scale);
 	t->set_constant("close_offset","GraphNode", 18 *scale);
 	t->set_constant("port_offset","GraphNode", 3 *scale);
 	t->set_constant("port_offset","GraphNode", 3 *scale);
 
 

二进制
scene/resources/default_theme/graph_node.png


二进制
scene/resources/default_theme/graph_node_selected.png


文件差异内容过多而无法显示
+ 4 - 4
scene/resources/default_theme/theme_data.h


+ 20 - 2
tools/editor/code_editor.cpp

@@ -1051,7 +1051,11 @@ void CodeTextEditor::_code_complete_timer_timeout() {
 void CodeTextEditor::_complete_request() {
 void CodeTextEditor::_complete_request() {
 
 
 	List<String> entries;
 	List<String> entries;
-	_code_complete_script(text_editor->get_text_for_completion(),&entries);
+	String ctext = text_editor->get_text_for_completion();
+	_code_complete_script(ctext,&entries);
+	if (code_complete_func) {
+		code_complete_func(code_complete_ud,ctext,&entries);
+	}
 	// print_line("COMPLETE: "+p_request);
 	// print_line("COMPLETE: "+p_request);
 	if (entries.size()==0)
 	if (entries.size()==0)
 		return;
 		return;
@@ -1135,13 +1139,16 @@ void CodeTextEditor::_text_changed_idle_timeout() {
 
 
 
 
 	_validate_script();
 	_validate_script();
+	emit_signal("validate_script");
 }
 }
 
 
 void CodeTextEditor::_notification(int p_what) {
 void CodeTextEditor::_notification(int p_what) {
 
 
 
 
-	if (p_what==EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED)
+	if (p_what==EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
 		_load_theme_settings();
 		_load_theme_settings();
+		emit_signal("load_theme_settings");
+	}
 	if (p_what==NOTIFICATION_ENTER_TREE) {
 	if (p_what==NOTIFICATION_ENTER_TREE) {
 		_update_font();
 		_update_font();
 	}
 	}
@@ -1157,10 +1164,21 @@ void CodeTextEditor::_bind_methods() {
 	ObjectTypeDB::bind_method("_code_complete_timer_timeout",&CodeTextEditor::_code_complete_timer_timeout);
 	ObjectTypeDB::bind_method("_code_complete_timer_timeout",&CodeTextEditor::_code_complete_timer_timeout);
 	ObjectTypeDB::bind_method("_complete_request",&CodeTextEditor::_complete_request);
 	ObjectTypeDB::bind_method("_complete_request",&CodeTextEditor::_complete_request);
 	ObjectTypeDB::bind_method("_font_resize_timeout",&CodeTextEditor::_font_resize_timeout);
 	ObjectTypeDB::bind_method("_font_resize_timeout",&CodeTextEditor::_font_resize_timeout);
+
+	ADD_SIGNAL(MethodInfo("validate_script"));
+	ADD_SIGNAL(MethodInfo("load_theme_settings"));
+
 }
 }
 
 
+void CodeTextEditor::set_code_complete_func(CodeTextEditorCodeCompleteFunc p_code_complete_func,void * p_ud) {
+	code_complete_func=p_code_complete_func;
+	code_complete_ud=p_ud;
+}
+
+
 CodeTextEditor::CodeTextEditor() {
 CodeTextEditor::CodeTextEditor() {
 
 
+	code_complete_func=NULL;
 	ED_SHORTCUT("script_editor/zoom_in", TTR("Zoom In"), KEY_MASK_CMD|KEY_EQUAL);
 	ED_SHORTCUT("script_editor/zoom_in", TTR("Zoom In"), KEY_MASK_CMD|KEY_EQUAL);
 	ED_SHORTCUT("script_editor/zoom_out", TTR("Zoom Out"), KEY_MASK_CMD|KEY_MINUS);
 	ED_SHORTCUT("script_editor/zoom_out", TTR("Zoom Out"), KEY_MASK_CMD|KEY_MINUS);
 	ED_SHORTCUT("script_editor/reset_zoom", TTR("Reset Zoom"), KEY_MASK_CMD|KEY_0);
 	ED_SHORTCUT("script_editor/reset_zoom", TTR("Reset Zoom"), KEY_MASK_CMD|KEY_0);

+ 14 - 3
tools/editor/code_editor.h

@@ -189,6 +189,8 @@ public:
 };
 };
 
 
 
 
+typedef void (*CodeTextEditorCodeCompleteFunc)(void* p_ud,const String& p_code, List<String>* r_options);
+
 class CodeTextEditor : public VBoxContainer {
 class CodeTextEditor : public VBoxContainer {
 
 
 	OBJ_TYPE(CodeTextEditor,VBoxContainer);
 	OBJ_TYPE(CodeTextEditor,VBoxContainer);
@@ -218,13 +220,16 @@ class CodeTextEditor : public VBoxContainer {
 	void _zoom_out();
 	void _zoom_out();
 	void _reset_zoom();
 	void _reset_zoom();
 
 
+
+	CodeTextEditorCodeCompleteFunc code_complete_func;
+	void *code_complete_ud;
+
 protected:
 protected:
 
 
-	void set_error(const String& p_error);
 
 
 	virtual void _load_theme_settings() {}
 	virtual void _load_theme_settings() {}
-	virtual void _validate_script()=0;
-	virtual void _code_complete_script(const String& p_code, List<String>* r_options) {};
+	virtual void _validate_script() {}
+	virtual void _code_complete_script(const String& p_code, List<String>* r_options) {}
 
 
 	void _text_changed_idle_timeout();
 	void _text_changed_idle_timeout();
 	void _code_complete_timer_timeout();
 	void _code_complete_timer_timeout();
@@ -235,10 +240,16 @@ protected:
 
 
 public:
 public:
 
 
+	void set_error(const String& p_error);
+	void update_line_and_column() { _line_col_changed(); }
 	TextEdit *get_text_edit() { return text_editor; }
 	TextEdit *get_text_edit() { return text_editor; }
 	FindReplaceBar *get_find_replace_bar() { return find_replace_bar; }
 	FindReplaceBar *get_find_replace_bar() { return find_replace_bar; }
 	virtual void apply_code() {}
 	virtual void apply_code() {}
 
 
+
+	void set_code_complete_func(CodeTextEditorCodeCompleteFunc p_code_complete_func, void * p_ud);
+
+
 	CodeTextEditor();
 	CodeTextEditor();
 };
 };
 
 

+ 3 - 0
tools/editor/editor_node.cpp

@@ -86,6 +86,7 @@
 #include "plugins/collision_polygon_editor_plugin.h"
 #include "plugins/collision_polygon_editor_plugin.h"
 #include "plugins/collision_polygon_2d_editor_plugin.h"
 #include "plugins/collision_polygon_2d_editor_plugin.h"
 #include "plugins/script_editor_plugin.h"
 #include "plugins/script_editor_plugin.h"
+#include "plugins/script_text_editor.h"
 #include "plugins/path_2d_editor_plugin.h"
 #include "plugins/path_2d_editor_plugin.h"
 #include "plugins/particles_editor_plugin.h"
 #include "plugins/particles_editor_plugin.h"
 #include "plugins/particles_2d_editor_plugin.h"
 #include "plugins/particles_2d_editor_plugin.h"
@@ -6443,6 +6444,8 @@ EditorNode::EditorNode() {
 	add_editor_plugin( memnew( SpatialEditorPlugin(this) ) );
 	add_editor_plugin( memnew( SpatialEditorPlugin(this) ) );
 	add_editor_plugin( memnew( ScriptEditorPlugin(this) ) );
 	add_editor_plugin( memnew( ScriptEditorPlugin(this) ) );
 
 
+	ScriptTextEditor::register_editor(); //register one for text scripts
+
 	if (StreamPeerSSL::is_available()) {
 	if (StreamPeerSSL::is_available()) {
 		add_editor_plugin( memnew( AssetLibraryEditorPlugin(this) ) );
 		add_editor_plugin( memnew( AssetLibraryEditorPlugin(this) ) );
 	} else {
 	} else {

二进制
tools/editor/icons/2x/icon_uninstance.png


二进制
tools/editor/icons/2x/icon_visual_script.png


二进制
tools/editor/icons/icon_mini_aabb.png


二进制
tools/editor/icons/icon_mini_array.png


二进制
tools/editor/icons/icon_mini_boolean.png


二进制
tools/editor/icons/icon_mini_color.png


二进制
tools/editor/icons/icon_mini_color_array.png


二进制
tools/editor/icons/icon_mini_dictionary.png


二进制
tools/editor/icons/icon_mini_float.png


二进制
tools/editor/icons/icon_mini_float_array.png


二进制
tools/editor/icons/icon_mini_image.png


二进制
tools/editor/icons/icon_mini_input.png


二进制
tools/editor/icons/icon_mini_int_array.png


二进制
tools/editor/icons/icon_mini_integer.png


二进制
tools/editor/icons/icon_mini_matrix3.png


二进制
tools/editor/icons/icon_mini_matrix32.png


二进制
tools/editor/icons/icon_mini_object.png


二进制
tools/editor/icons/icon_mini_path.png


二进制
tools/editor/icons/icon_mini_plane.png


二进制
tools/editor/icons/icon_mini_quat.png


二进制
tools/editor/icons/icon_mini_raw_array.png


二进制
tools/editor/icons/icon_mini_rect2.png


二进制
tools/editor/icons/icon_mini_rid.png


二进制
tools/editor/icons/icon_mini_string.png


二进制
tools/editor/icons/icon_mini_string_array.png


二进制
tools/editor/icons/icon_mini_transform.png


二进制
tools/editor/icons/icon_mini_variant.png


二进制
tools/editor/icons/icon_mini_vector2.png


二进制
tools/editor/icons/icon_mini_vector2_array.png


二进制
tools/editor/icons/icon_mini_vector3.png


二进制
tools/editor/icons/icon_mini_vector3_array.png


二进制
tools/editor/icons/icon_override.png


二进制
tools/editor/icons/icon_uninstance.png


二进制
tools/editor/icons/icon_variant.png


二进制
tools/editor/icons/icon_visual_script.png


二进制
tools/editor/icons/icon_visual_shader_port.png


文件差异内容过多而无法显示
+ 52 - 823
tools/editor/plugins/script_editor_plugin.cpp


+ 45 - 64
tools/editor/plugins/script_editor_plugin.h

@@ -73,40 +73,43 @@ public:
 
 
 class ScriptEditorDebugger;
 class ScriptEditorDebugger;
 
 
-class ScriptTextEditor : public CodeTextEditor {
 
 
-	OBJ_TYPE( ScriptTextEditor, CodeTextEditor );
 
 
-	Ref<Script> script;
+class ScriptEditorBase : public Control {
 
 
+	OBJ_TYPE( ScriptEditorBase, Control );
 
 
-	Vector<String> functions;
-
-
-protected:
-
-
-
-	virtual void _validate_script();
-	virtual void _code_complete_script(const String& p_code, List<String>* r_options);
-	virtual void _load_theme_settings();
-	void _notification(int p_what);
-	static void _bind_methods();
+public:
 
 
+	virtual void apply_code()=0;
+	virtual Ref<Script> get_edited_script() const=0;
+	virtual Vector<String> get_functions()=0;
+	virtual void set_edited_script(const Ref<Script>& p_script)=0;
+	virtual void reload_text()=0;
+	virtual String get_name()=0;
+	virtual Ref<Texture> get_icon()=0;
+	virtual bool is_unsaved()=0;
+	virtual Variant get_edit_state()=0;
+	virtual void set_edit_state(const Variant& p_state)=0;
+	virtual void goto_line(int p_line)=0;
+	virtual void trim_trailing_whitespace()=0;
+	virtual void ensure_focus()=0;
+	virtual void tag_saved_version()=0;
+	virtual void reload(bool p_soft)=0;
+	virtual void get_breakpoints(List<int> *p_breakpoints)=0;
+	virtual bool goto_method(const String& p_method)=0;
+	virtual void add_callback(const String& p_function,StringArray p_args)=0;
+	virtual void update_settings()=0;
+
+	virtual void set_tooltip_request_func(String p_method,Object* p_obj)=0;
+	virtual Control *get_edit_menu()=0;
+
+	ScriptEditorBase() {}
+};
 
 
-public:
 
 
-	virtual void apply_code();
-	Ref<Script> get_edited_script() const;
-	Vector<String> get_functions() ;
-	void set_edited_script(const Ref<Script>& p_script);
-	void reload_text();
-	String get_name() ;
-	Ref<Texture> get_icon() ;
-	bool is_unsaved();
-	ScriptTextEditor();
+typedef ScriptEditorBase* (*CreateScriptEditorFunc)(const Ref<Script>& p_script);
 
 
-};
 
 
 class EditorScriptCodeCompletionCache;
 class EditorScriptCodeCompletionCache;
 
 
@@ -128,43 +131,19 @@ class ScriptEditor : public VBoxContainer {
 		FILE_SAVE_THEME_AS,
 		FILE_SAVE_THEME_AS,
 		FILE_CLOSE,
 		FILE_CLOSE,
 		CLOSE_DOCS,
 		CLOSE_DOCS,
-		EDIT_UNDO,
-		EDIT_REDO,
-		EDIT_CUT,
-		EDIT_COPY,
-		EDIT_PASTE,
-		EDIT_SELECT_ALL,
-		EDIT_COMPLETE,
-		EDIT_AUTO_INDENT,
-		EDIT_TRIM_TRAILING_WHITESAPCE,
-		EDIT_TOGGLE_COMMENT,
-		EDIT_MOVE_LINE_UP,
-		EDIT_MOVE_LINE_DOWN,
-		EDIT_INDENT_RIGHT,
-		EDIT_INDENT_LEFT,
-		EDIT_CLONE_DOWN,
 		FILE_TOOL_RELOAD,
 		FILE_TOOL_RELOAD,
 		FILE_TOOL_RELOAD_SOFT,
 		FILE_TOOL_RELOAD_SOFT,
-		SEARCH_FIND,
-		SEARCH_FIND_NEXT,
-		SEARCH_FIND_PREV,
-		SEARCH_REPLACE,
-		SEARCH_LOCATE_FUNCTION,
-		SEARCH_GOTO_LINE,
-		SEARCH_HELP,
-		SEARCH_CLASSES,
-		SEARCH_WEBSITE,
-		DEBUG_TOGGLE_BREAKPOINT,
-		DEBUG_REMOVE_ALL_BREAKPOINTS,
-		DEBUG_GOTO_NEXT_BREAKPOINT,
-		DEBUG_GOTO_PREV_BREAKPOINT,
 		DEBUG_NEXT,
 		DEBUG_NEXT,
 		DEBUG_STEP,
 		DEBUG_STEP,
 		DEBUG_BREAK,
 		DEBUG_BREAK,
 		DEBUG_CONTINUE,
 		DEBUG_CONTINUE,
 		DEBUG_SHOW,
 		DEBUG_SHOW,
 		DEBUG_SHOW_KEEP_OPEN,
 		DEBUG_SHOW_KEEP_OPEN,
-		HELP_CONTEXTUAL,
+		SEARCH_HELP,
+		SEARCH_CLASSES,
+		SEARCH_WEBSITE,
+		HELP_SEARCH_FIND,
+		HELP_SEARCH_FIND_NEXT,
 		WINDOW_MOVE_LEFT,
 		WINDOW_MOVE_LEFT,
 		WINDOW_MOVE_RIGHT,
 		WINDOW_MOVE_RIGHT,
 		WINDOW_NEXT,
 		WINDOW_NEXT,
@@ -175,10 +154,8 @@ class ScriptEditor : public VBoxContainer {
 	HBoxContainer *menu_hb;
 	HBoxContainer *menu_hb;
 	MenuButton *file_menu;
 	MenuButton *file_menu;
 	MenuButton *edit_menu;
 	MenuButton *edit_menu;
-	MenuButton *search_menu;
 	MenuButton *script_search_menu;
 	MenuButton *script_search_menu;
 	MenuButton *debug_menu;
 	MenuButton *debug_menu;
-	MenuButton *help_menu;
 	Timer *autosave_timer;
 	Timer *autosave_timer;
 	uint64_t idle;
 	uint64_t idle;
 
 
@@ -191,7 +168,6 @@ class ScriptEditor : public VBoxContainer {
 	HSplitContainer *script_split;
 	HSplitContainer *script_split;
 	TabContainer *tab_container;
 	TabContainer *tab_container;
 	EditorFileDialog *file_dialog;
 	EditorFileDialog *file_dialog;
-	GotoLineDialog *goto_line_dialog;
 	ConfirmationDialog *erase_tab_confirm;
 	ConfirmationDialog *erase_tab_confirm;
 	ScriptCreateDialog *script_create_dialog;
 	ScriptCreateDialog *script_create_dialog;
 	ScriptEditorDebugger* debugger;
 	ScriptEditorDebugger* debugger;
@@ -205,13 +181,17 @@ class ScriptEditor : public VBoxContainer {
 	ToolButton *script_back;
 	ToolButton *script_back;
 	ToolButton *script_forward;
 	ToolButton *script_forward;
 
 
+	enum {
+		SCRIPT_EDITOR_FUNC_MAX=32
+	};
+
+	static int script_editor_func_count;
+	static CreateScriptEditorFunc script_editor_funcs[SCRIPT_EDITOR_FUNC_MAX];
 
 
 	struct ScriptHistory {
 	struct ScriptHistory {
 
 
 		Control *control;
 		Control *control;
-		int scroll_pos;
-		int cursor_column;
-		int cursor_row;
+		Variant state;
 	};
 	};
 
 
 	Vector<ScriptHistory> history;
 	Vector<ScriptHistory> history;
@@ -246,7 +226,7 @@ class ScriptEditor : public VBoxContainer {
 	bool auto_reload_running_scripts;
 	bool auto_reload_running_scripts;
 	void _live_auto_reload_running_scripts();
 	void _live_auto_reload_running_scripts();
 
 
-	ScriptEditorQuickOpen *quick_open;
+	void _update_selected_editor_menu();
 
 
 	EditorScriptCodeCompletionCache *completion_cache;
 	EditorScriptCodeCompletionCache *completion_cache;
 
 
@@ -286,6 +266,7 @@ class ScriptEditor : public VBoxContainer {
 
 
 	void _unhandled_input(const InputEvent& p_event);
 	void _unhandled_input(const InputEvent& p_event);
 
 
+	void _help_search(String p_text);
 
 
 	void _history_forward();
 	void _history_forward();
 	void _history_back();
 	void _history_back();
@@ -323,8 +304,7 @@ public:
 
 
 	void get_breakpoints(List<String> *p_breakpoints);
 	void get_breakpoints(List<String> *p_breakpoints);
 
 
-	void swap_lines(TextEdit *tx, int line1, int line2);
-	void _breakpoint_toggled(const int p_row);
+	//void swap_lines(TextEdit *tx, int line1, int line2);
 
 
 	void save_all_scripts();
 	void save_all_scripts();
 
 
@@ -342,6 +322,7 @@ public:
 	ScriptEditorDebugger *get_debugger() { return debugger; }
 	ScriptEditorDebugger *get_debugger() { return debugger; }
 	void set_live_auto_reload_running_scripts(bool p_enabled);
 	void set_live_auto_reload_running_scripts(bool p_enabled);
 
 
+	static void register_create_script_editor_function(CreateScriptEditorFunc p_func);
 	ScriptEditor(EditorNode *p_editor);
 	ScriptEditor(EditorNode *p_editor);
 	~ScriptEditor();
 	~ScriptEditor();
 };
 };

+ 1057 - 0
tools/editor/plugins/script_text_editor.cpp

@@ -0,0 +1,1057 @@
+#include "script_text_editor.h"
+#include "tools/editor/editor_settings.h"
+#include "os/keyboard.h""
+#include "tools/editor/script_editor_debugger.h"
+Vector<String> ScriptTextEditor::get_functions()  {
+
+
+	String errortxt;
+	int line=-1,col;
+	TextEdit *te=code_editor->get_text_edit();
+	String text = te->get_text();
+	List<String> fnc;
+
+	if (script->get_language()->validate(text,line,col,errortxt,script->get_path(),&fnc)) {
+
+		//if valid rewrite functions to latest
+		functions.clear();
+		for (List<String>::Element *E=fnc.front();E;E=E->next()) {
+
+			functions.push_back(E->get());
+		}
+
+
+	}
+
+	return functions;
+}
+
+void ScriptTextEditor::apply_code() {
+
+	if (script.is_null())
+		return;
+//	print_line("applying code");
+	script->set_source_code(code_editor->get_text_edit()->get_text());
+	script->update_exports();
+}
+
+Ref<Script> ScriptTextEditor::get_edited_script() const {
+
+	return script;
+}
+
+bool ScriptTextEditor::goto_method(const String& p_method) {
+
+
+	Vector<String> functions = get_functions();
+
+	String method_search = p_method + ":";
+
+	for (int i=0;i<functions.size();i++) {
+		String function=functions[i];
+
+		if (function.begins_with(method_search)) {
+
+			int line=function.get_slice(":",1).to_int();
+			goto_line(line-1);
+			return true;
+		}
+	}
+
+	return false;
+}
+
+void ScriptTextEditor::_load_theme_settings() {
+
+	TextEdit *text_edit = code_editor->get_text_edit();
+
+	text_edit->clear_colors();
+
+	/* keyword color */
+
+
+	text_edit->set_custom_bg_color(EDITOR_DEF("text_editor/background_color",Color(0,0,0,0)));
+	text_edit->add_color_override("completion_background_color", EDITOR_DEF("text_editor/completion_background_color", Color(0,0,0,0)));
+	text_edit->add_color_override("completion_selected_color", EDITOR_DEF("text_editor/completion_selected_color", Color::html("434244")));
+	text_edit->add_color_override("completion_existing_color", EDITOR_DEF("text_editor/completion_existing_color", Color::html("21dfdfdf")));
+	text_edit->add_color_override("completion_scroll_color", EDITOR_DEF("text_editor/completion_scroll_color", Color::html("ffffff")));
+	text_edit->add_color_override("completion_font_color", EDITOR_DEF("text_editor/completion_font_color", Color::html("aaaaaa")));
+	text_edit->add_color_override("font_color",EDITOR_DEF("text_editor/text_color",Color(0,0,0)));
+	text_edit->add_color_override("line_number_color",EDITOR_DEF("text_editor/line_number_color",Color(0,0,0)));
+	text_edit->add_color_override("caret_color",EDITOR_DEF("text_editor/caret_color",Color(0,0,0)));
+	text_edit->add_color_override("caret_background_color",EDITOR_DEF("text_editor/caret_background_color",Color(0,0,0)));
+	text_edit->add_color_override("font_selected_color",EDITOR_DEF("text_editor/text_selected_color",Color(1,1,1)));
+	text_edit->add_color_override("selection_color",EDITOR_DEF("text_editor/selection_color",Color(0.2,0.2,1)));
+	text_edit->add_color_override("brace_mismatch_color",EDITOR_DEF("text_editor/brace_mismatch_color",Color(1,0.2,0.2)));
+	text_edit->add_color_override("current_line_color",EDITOR_DEF("text_editor/current_line_color",Color(0.3,0.5,0.8,0.15)));
+	text_edit->add_color_override("word_highlighted_color",EDITOR_DEF("text_editor/word_highlighted_color",Color(0.8,0.9,0.9,0.15)));
+	text_edit->add_color_override("number_color",EDITOR_DEF("text_editor/number_color",Color(0.9,0.6,0.0,2)));
+	text_edit->add_color_override("function_color",EDITOR_DEF("text_editor/function_color",Color(0.4,0.6,0.8)));
+	text_edit->add_color_override("member_variable_color",EDITOR_DEF("text_editor/member_variable_color",Color(0.9,0.3,0.3)));
+	text_edit->add_color_override("mark_color", EDITOR_DEF("text_editor/mark_color", Color(1.0,0.4,0.4,0.4)));
+	text_edit->add_color_override("breakpoint_color", EDITOR_DEF("text_editor/breakpoint_color", Color(0.8,0.8,0.4,0.2)));
+	text_edit->add_color_override("search_result_color",EDITOR_DEF("text_editor/search_result_color",Color(0.05,0.25,0.05,1)));
+	text_edit->add_color_override("search_result_border_color",EDITOR_DEF("text_editor/search_result_border_color",Color(0.1,0.45,0.1,1)));
+	text_edit->add_constant_override("line_spacing", EDITOR_DEF("text_editor/line_spacing",4));
+
+	Color keyword_color= EDITOR_DEF("text_editor/keyword_color",Color(0.5,0.0,0.2));
+
+	List<String> keywords;
+	script->get_language()->get_reserved_words(&keywords);
+	for(List<String>::Element *E=keywords.front();E;E=E->next()) {
+
+		text_edit->add_keyword_color(E->get(),keyword_color);
+	}
+
+	//colorize core types
+	Color basetype_color= EDITOR_DEF("text_editor/base_type_color",Color(0.3,0.3,0.0));
+
+	text_edit->add_keyword_color("Vector2",basetype_color);
+	text_edit->add_keyword_color("Vector3",basetype_color);
+	text_edit->add_keyword_color("Plane",basetype_color);
+	text_edit->add_keyword_color("Quat",basetype_color);
+	text_edit->add_keyword_color("AABB",basetype_color);
+	text_edit->add_keyword_color("Matrix3",basetype_color);
+	text_edit->add_keyword_color("Transform",basetype_color);
+	text_edit->add_keyword_color("Color",basetype_color);
+	text_edit->add_keyword_color("Image",basetype_color);
+	text_edit->add_keyword_color("InputEvent",basetype_color);
+	text_edit->add_keyword_color("Rect2",basetype_color);
+	text_edit->add_keyword_color("NodePath",basetype_color);
+
+	//colorize engine types
+	Color type_color= EDITOR_DEF("text_editor/engine_type_color",Color(0.0,0.2,0.4));
+
+	List<StringName> types;
+	ObjectTypeDB::get_type_list(&types);
+
+	for(List<StringName>::Element *E=types.front();E;E=E->next()) {
+
+		String n = E->get();
+		if (n.begins_with("_"))
+			n = n.substr(1, n.length());
+
+		text_edit->add_keyword_color(n,type_color);
+	}
+
+	//colorize comments
+	Color comment_color = EDITOR_DEF("text_editor/comment_color",Color::hex(0x797e7eff));
+	List<String> comments;
+	script->get_language()->get_comment_delimiters(&comments);
+
+	for(List<String>::Element *E=comments.front();E;E=E->next()) {
+
+		String comment = E->get();
+		String beg = comment.get_slice(" ",0);
+		String end = comment.get_slice_count(" ")>1?comment.get_slice(" ",1):String();
+
+		text_edit->add_color_region(beg,end,comment_color,end=="");
+	}
+
+	//colorize strings
+	Color string_color = EDITOR_DEF("text_editor/string_color",Color::hex(0x6b6f00ff));
+	List<String> strings;
+	script->get_language()->get_string_delimiters(&strings);
+
+	for (List<String>::Element *E=strings.front();E;E=E->next()) {
+
+		String string = E->get();
+		String beg = string.get_slice(" ",0);
+		String end = string.get_slice_count(" ")>1?string.get_slice(" ",1):String();
+		text_edit->add_color_region(beg,end,string_color,end=="");
+	}
+
+	//colorize symbols
+	Color symbol_color= EDITOR_DEF("text_editor/symbol_color",Color::hex(0x005291ff));
+	text_edit->set_symbol_color(symbol_color);
+
+}
+
+
+void ScriptTextEditor::reload_text() {
+
+	ERR_FAIL_COND(script.is_null())	;
+
+	TextEdit *te = code_editor->get_text_edit();
+	int column = te->cursor_get_column();
+	int row = te->cursor_get_line();
+	int h = te->get_h_scroll();
+	int v = te->get_v_scroll();
+
+	te->set_text(script->get_source_code());
+	te->clear_undo_history();
+	te->cursor_set_line(row);
+	te->cursor_set_column(column);
+	te->set_h_scroll(h);
+	te->set_v_scroll(v);
+
+	te->tag_saved_version();
+
+	code_editor->update_line_and_column();
+
+}
+
+void ScriptTextEditor::_notification(int p_what) {
+
+	if (p_what==NOTIFICATION_READY) {
+
+		//emit_signal("name_changed");
+	}
+}
+
+void ScriptTextEditor::add_callback(const String& p_function,StringArray p_args) {
+
+	String code = code_editor->get_text_edit()->get_text();
+	int pos = script->get_language()->find_function(p_function,code);
+	if (pos==-1) {
+		//does not exist
+		code_editor->get_text_edit()->deselect();
+		pos=code_editor->get_text_edit()->get_line_count()+2;
+		String func = script->get_language()->make_function("",p_function,p_args);
+		//code=code+func;
+		code_editor->get_text_edit()->cursor_set_line(pos+1);
+		code_editor->get_text_edit()->cursor_set_column(1000000); //none shall be that big
+		code_editor->get_text_edit()->insert_text_at_cursor("\n\n"+func);
+	}
+	code_editor->get_text_edit()->cursor_set_line(pos);
+	code_editor->get_text_edit()->cursor_set_column(1);
+}
+
+void ScriptTextEditor::update_settings() {
+
+	code_editor->get_text_edit()->set_auto_brace_completion(EditorSettings::get_singleton()->get("text_editor/auto_brace_complete"));
+	code_editor->get_text_edit()->set_scroll_pass_end_of_file(EditorSettings::get_singleton()->get("text_editor/scroll_past_end_of_file"));
+	code_editor->get_text_edit()->set_tab_size(EditorSettings::get_singleton()->get("text_editor/tab_size"));
+	code_editor->get_text_edit()->set_draw_tabs(EditorSettings::get_singleton()->get("text_editor/draw_tabs"));
+	code_editor->get_text_edit()->set_show_line_numbers(EditorSettings::get_singleton()->get("text_editor/show_line_numbers"));
+	code_editor->get_text_edit()->set_syntax_coloring(EditorSettings::get_singleton()->get("text_editor/syntax_highlighting"));
+	code_editor->get_text_edit()->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/highlight_all_occurrences"));
+	code_editor->get_text_edit()->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/caret_blink"));
+	code_editor->get_text_edit()->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/caret_blink_speed"));
+	code_editor->get_text_edit()->set_draw_breakpoint_gutter(EditorSettings::get_singleton()->get("text_editor/show_breakpoint_gutter"));
+	code_editor->get_text_edit()->cursor_set_block_mode(EditorSettings::get_singleton()->get("text_editor/block_caret"));
+}
+
+bool ScriptTextEditor::is_unsaved()  {
+
+	return code_editor->get_text_edit()->get_version()!=code_editor->get_text_edit()->get_saved_version();
+}
+
+Variant ScriptTextEditor::get_edit_state() {
+
+	Dictionary state;
+
+	state["scroll_pos"]=code_editor->get_text_edit()->get_v_scroll();
+	state["column"]=code_editor->get_text_edit()->cursor_get_column();
+	state["row"]=code_editor->get_text_edit()->cursor_get_line();
+
+	return state;
+}
+
+void ScriptTextEditor::trim_trailing_whitespace() {
+
+	TextEdit *tx = code_editor->get_text_edit();
+
+	bool trimed_whitespace = false;
+	for (int i = 0; i < tx->get_line_count(); i++) {
+		String line = tx->get_line(i);
+		if (line.ends_with(" ") || line.ends_with("\t")) {
+
+			if (!trimed_whitespace) {
+				tx->begin_complex_operation();
+				trimed_whitespace = true;
+			}
+
+			int end = 0;
+			for (int j = line.length() - 1; j > -1; j--) {
+				if (line[j] != ' ' && line[j] != '\t') {
+					end = j+1;
+					break;
+				}
+			}
+			tx->set_line(i, line.substr(0, end));
+		}
+	}
+	if (trimed_whitespace) {
+		tx->end_complex_operation();
+		tx->update();
+	}
+}
+
+void ScriptTextEditor::tag_saved_version() {
+
+	code_editor->get_text_edit()->tag_saved_version();
+}
+
+void ScriptTextEditor::goto_line(int p_line) {
+	code_editor->get_text_edit()->cursor_set_line(p_line);
+}
+
+void ScriptTextEditor::ensure_focus() {
+
+	code_editor->get_text_edit()->grab_focus();
+}
+
+void ScriptTextEditor::set_edit_state(const Variant& p_state) {
+
+	Dictionary state=p_state;
+	code_editor->get_text_edit()->set_v_scroll(state["scroll_pos"]);
+	code_editor->get_text_edit()->cursor_set_column( state["column"]);
+	code_editor->get_text_edit()->cursor_set_line( state["row"] );
+	code_editor->get_text_edit()->grab_focus();
+
+	//int scroll_pos;
+	//int cursor_column;
+	//int cursor_row;
+}
+
+String ScriptTextEditor::get_name()  {
+	String name;
+
+	if (script->get_path().find("local://")==-1 && script->get_path().find("::")==-1) {
+		name=script->get_path().get_file();
+		if (is_unsaved()) {
+			name+="(*)";
+		}
+	} else if (script->get_name()!="")
+		name=script->get_name();
+	else
+		name=script->get_type()+"("+itos(script->get_instance_ID())+")";
+
+	return name;
+
+}
+
+Ref<Texture> ScriptTextEditor::get_icon() {
+
+	if (get_parent_control() && get_parent_control()->has_icon(script->get_type(),"EditorIcons")) {
+		return get_parent_control()->get_icon(script->get_type(),"EditorIcons");
+	}
+
+	return Ref<Texture>();
+}
+
+
+
+void ScriptTextEditor::set_edited_script(const Ref<Script>& p_script) {
+
+	ERR_FAIL_COND(!script.is_null());
+
+	script=p_script;
+
+
+	_load_theme_settings();
+
+	code_editor->get_text_edit()->set_text(script->get_source_code());
+	code_editor->get_text_edit()->clear_undo_history();
+	code_editor->get_text_edit()->tag_saved_version();
+
+	emit_signal("name_changed");
+	code_editor->update_line_and_column();
+}
+
+
+void ScriptTextEditor::_validate_script() {
+
+	String errortxt;
+	int line=-1,col;
+	TextEdit *te=code_editor->get_text_edit();
+
+	String text = te->get_text();
+	List<String> fnc;
+
+	if (!script->get_language()->validate(text,line,col,errortxt,script->get_path(),&fnc)) {
+		String error_text="error("+itos(line)+","+itos(col)+"): "+errortxt;
+		code_editor->set_error(error_text);
+	} else {
+		code_editor->set_error("");
+		line=-1;
+		if (!script->is_tool()) {
+			script->set_source_code(text);
+			script->update_exports();
+			//script->reload(); //will update all the variables in property editors
+		}
+
+		functions.clear();
+		for (List<String>::Element *E=fnc.front();E;E=E->next()) {
+
+			functions.push_back(E->get());
+		}
+
+	}
+
+	line--;
+	for(int i=0;i<te->get_line_count();i++) {
+		te->set_line_as_marked(i,line==i);
+	}
+
+	emit_signal("name_changed");
+}
+
+
+static Node* _find_node_for_script(Node* p_base, Node*p_current, const Ref<Script>& p_script) {
+
+	if (p_current->get_owner()!=p_base && p_base!=p_current)
+		return NULL;
+	Ref<Script> c = p_current->get_script();
+	if (c==p_script)
+		return p_current;
+	for(int i=0;i<p_current->get_child_count();i++) {
+		Node *found = _find_node_for_script(p_base,p_current->get_child(i),p_script);
+		if (found)
+			return found;
+	}
+
+	return NULL;
+}
+
+static void _find_changed_scripts_for_external_editor(Node* p_base, Node*p_current, Set<Ref<Script> > &r_scripts) {
+
+	if (p_current->get_owner()!=p_base && p_base!=p_current)
+		return;
+	Ref<Script> c = p_current->get_script();
+
+	if (c.is_valid())
+		r_scripts.insert(c);
+
+	for(int i=0;i<p_current->get_child_count();i++) {
+		_find_changed_scripts_for_external_editor(p_base,p_current->get_child(i),r_scripts);
+	}
+
+}
+
+void ScriptEditor::_update_modified_scripts_for_external_editor(Ref<Script> p_for_script) {
+
+	if (!bool(EditorSettings::get_singleton()->get("external_editor/use_external_editor")))
+		return;
+
+	Set<Ref<Script> > scripts;
+
+	Node *base = get_tree()->get_edited_scene_root();
+	if (base) {
+		_find_changed_scripts_for_external_editor(base,base,scripts);
+	}
+
+	for (Set<Ref<Script> >::Element *E=scripts.front();E;E=E->next()) {
+
+		Ref<Script> script = E->get();
+
+		if (p_for_script.is_valid() && p_for_script!=script)
+			continue;
+
+		if (script->get_path()=="" || script->get_path().find("local://")!=-1 || script->get_path().find("::")!=-1) {
+
+			continue; //internal script, who cares, though weird
+		}
+
+		uint64_t last_date = script->get_last_modified_time();
+		uint64_t date = FileAccess::get_modified_time(script->get_path());
+
+		if (last_date!=date) {
+
+			Ref<Script> rel_script = ResourceLoader::load(script->get_path(),script->get_type(),true);
+			ERR_CONTINUE(!rel_script.is_valid());
+			script->set_source_code( rel_script->get_source_code() );
+			script->set_last_modified_time( rel_script->get_last_modified_time() );
+			script->update_exports();
+		}
+
+	}
+}
+
+
+void ScriptTextEditor::_code_complete_scripts(void* p_ud,const String& p_code, List<String>* r_options) {
+
+	ScriptTextEditor *ste = (ScriptTextEditor *)p_ud;
+	ste->_code_complete_script(p_code,r_options);
+}
+
+void ScriptTextEditor::_code_complete_script(const String& p_code, List<String>* r_options) {
+
+	Node *base = get_tree()->get_edited_scene_root();
+	if (base) {
+		base = _find_node_for_script(base,base,script);
+	}
+	String hint;
+	Error err = script->get_language()->complete_code(p_code,script->get_path().get_base_dir(),base,r_options,hint);
+	if (hint!="") {
+		code_editor->get_text_edit()->set_code_hint(hint);
+	}
+
+}
+
+void ScriptTextEditor::_breakpoint_toggled(int p_row) {
+
+	ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(script->get_path(),p_row+1,code_editor->get_text_edit()->is_line_set_as_breakpoint(p_row));
+
+}
+
+static void swap_lines(TextEdit *tx, int line1, int line2)
+{
+    String tmp = tx->get_line(line1);
+    String tmp2 = tx->get_line(line2);
+    tx->set_line(line2, tmp);
+    tx->set_line(line1, tmp2);
+
+    tx->cursor_set_line(line2);
+}
+
+
+void ScriptTextEditor::_edit_option(int p_op) {
+
+	switch(p_op) {
+		case EDIT_UNDO: {
+			code_editor->get_text_edit()->undo();
+			code_editor->get_text_edit()->call_deferred("grab_focus");
+		} break;
+		case EDIT_REDO: {
+			code_editor->get_text_edit()->redo();
+			code_editor->get_text_edit()->call_deferred("grab_focus");
+		} break;
+		case EDIT_CUT: {
+
+			code_editor->get_text_edit()->cut();
+			code_editor->get_text_edit()->call_deferred("grab_focus");
+		} break;
+		case EDIT_COPY: {
+			code_editor->get_text_edit()->copy();
+			code_editor->get_text_edit()->call_deferred("grab_focus");
+
+		} break;
+		case EDIT_PASTE: {
+			code_editor->get_text_edit()->paste();
+			code_editor->get_text_edit()->call_deferred("grab_focus");
+
+		} break;
+		case EDIT_SELECT_ALL: {
+
+			code_editor->get_text_edit()->select_all();
+			code_editor->get_text_edit()->call_deferred("grab_focus");
+
+		} break;
+		case EDIT_MOVE_LINE_UP: {
+
+			TextEdit *tx = code_editor->get_text_edit();
+			Ref<Script> scr = script;
+			if (scr.is_null())
+				return;
+
+			tx->begin_complex_operation();
+			if (tx->is_selection_active())
+			{
+				int from_line = tx->get_selection_from_line();
+				int from_col  = tx->get_selection_from_column();
+				int to_line   = tx->get_selection_to_line();
+				int to_column = tx->get_selection_to_column();
+
+				for (int i = from_line; i <= to_line; i++)
+				{
+					int line_id = i;
+					int next_id = i - 1;
+
+					if (line_id == 0 || next_id < 0)
+						return;
+
+					swap_lines(tx, line_id, next_id);
+				}
+				int from_line_up = from_line > 0 ? from_line-1 : from_line;
+				int to_line_up   = to_line   > 0 ? to_line-1   : to_line;
+				tx->select(from_line_up, from_col, to_line_up, to_column);
+			}
+			else
+			{
+				int line_id = tx->cursor_get_line();
+				int next_id = line_id - 1;
+
+				if (line_id == 0 || next_id < 0)
+					return;
+
+				swap_lines(tx, line_id, next_id);
+			}
+			tx->end_complex_operation();
+			tx->update();
+
+		} break;
+		case EDIT_MOVE_LINE_DOWN: {
+
+			TextEdit *tx = code_editor->get_text_edit();
+			Ref<Script> scr = get_edited_script();
+			if (scr.is_null())
+				return;
+
+			tx->begin_complex_operation();
+			if (tx->is_selection_active())
+			{
+				int from_line = tx->get_selection_from_line();
+				int from_col  = tx->get_selection_from_column();
+				int to_line   = tx->get_selection_to_line();
+				int to_column = tx->get_selection_to_column();
+
+				for (int i = to_line; i >= from_line; i--)
+				{
+					int line_id = i;
+					int next_id = i + 1;
+
+					if (line_id == tx->get_line_count()-1 || next_id > tx->get_line_count())
+						return;
+
+					swap_lines(tx, line_id, next_id);
+				}
+				int from_line_down = from_line < tx->get_line_count() ? from_line+1 : from_line;
+				int to_line_down   = to_line   < tx->get_line_count() ? to_line+1   : to_line;
+				tx->select(from_line_down, from_col, to_line_down, to_column);
+			}
+			else
+			{
+				int line_id = tx->cursor_get_line();
+				int next_id = line_id + 1;
+
+				if (line_id == tx->get_line_count()-1 || next_id > tx->get_line_count())
+					return;
+
+				swap_lines(tx, line_id, next_id);
+			}
+			tx->end_complex_operation();
+			tx->update();
+
+		} break;
+		case EDIT_INDENT_LEFT: {
+
+			TextEdit *tx = code_editor->get_text_edit();
+			Ref<Script> scr = get_edited_script();
+			if (scr.is_null())
+				return;
+
+			tx->begin_complex_operation();
+			if (tx->is_selection_active())
+			{
+				tx->indent_selection_left();
+			}
+			else
+			{
+				int begin = tx->cursor_get_line();
+				String line_text = tx->get_line(begin);
+				// begins with tab
+				if (line_text.begins_with("\t"))
+				{
+					line_text = line_text.substr(1, line_text.length());
+					tx->set_line(begin, line_text);
+				}
+				// begins with 4 spaces
+				else if (line_text.begins_with("    "))
+				{
+					line_text = line_text.substr(4, line_text.length());
+					tx->set_line(begin, line_text);
+				}
+			}
+			tx->end_complex_operation();
+			tx->update();
+			//tx->deselect();
+
+		} break;
+		case EDIT_INDENT_RIGHT: {
+
+			TextEdit *tx = code_editor->get_text_edit();
+			Ref<Script> scr = get_edited_script();
+			if (scr.is_null())
+				return;
+
+			tx->begin_complex_operation();
+			if (tx->is_selection_active())
+			{
+				tx->indent_selection_right();
+			}
+			else
+			{
+				int begin = tx->cursor_get_line();
+				String line_text = tx->get_line(begin);
+				line_text = '\t' + line_text;
+				tx->set_line(begin, line_text);
+			}
+			tx->end_complex_operation();
+			tx->update();
+			//tx->deselect();
+
+		} break;
+		case EDIT_CLONE_DOWN: {
+
+			TextEdit *tx = code_editor->get_text_edit();
+			Ref<Script> scr = get_edited_script();
+			if (scr.is_null())
+				return;
+
+			int from_line = tx->cursor_get_line();
+			int to_line = tx->cursor_get_line();
+			int column = tx->cursor_get_column();
+
+			if (tx->is_selection_active()) {
+				from_line = tx->get_selection_from_line();
+				to_line = tx->get_selection_to_line();
+				column = tx->cursor_get_column();
+			}
+			int next_line = to_line + 1;
+
+			tx->begin_complex_operation();
+			for (int i = from_line; i <= to_line; i++) {
+
+				if (i >= tx->get_line_count() - 1) {
+						tx->set_line(i, tx->get_line(i) + "\n");
+				}
+				String line_clone = tx->get_line(i);
+				tx->insert_at(line_clone, next_line);
+				next_line++;
+			}
+
+			tx->cursor_set_column(column);
+			if (tx->is_selection_active()) {
+				tx->select(to_line + 1, tx->get_selection_from_column(), next_line - 1, tx->get_selection_to_column());
+			}
+
+			tx->end_complex_operation();
+			tx->update();
+
+		} break;
+		case EDIT_TOGGLE_COMMENT: {
+
+			TextEdit *tx = code_editor->get_text_edit();
+			Ref<Script> scr = get_edited_script();
+			if (scr.is_null())
+				return;
+
+
+			tx->begin_complex_operation();
+			if (tx->is_selection_active())
+			{
+				int begin = tx->get_selection_from_line();
+				int end = tx->get_selection_to_line();
+
+				// End of selection ends on the first column of the last line, ignore it.
+				if(tx->get_selection_to_column() == 0)
+					end -= 1;
+
+				for (int i = begin; i <= end; i++)
+				{
+					String line_text = tx->get_line(i);
+
+					if (line_text.begins_with("#"))
+						line_text = line_text.substr(1, line_text.length());
+					else
+						line_text = "#" + line_text;
+					tx->set_line(i, line_text);
+				}
+			}
+			else
+			{
+				int begin = tx->cursor_get_line();
+				String line_text = tx->get_line(begin);
+
+				if (line_text.begins_with("#"))
+					line_text = line_text.substr(1, line_text.length());
+				else
+					line_text = "#" + line_text;
+				tx->set_line(begin, line_text);
+			}
+			tx->end_complex_operation();
+			tx->update();
+			//tx->deselect();
+
+		} break;
+		case EDIT_COMPLETE: {
+
+			code_editor->get_text_edit()->query_code_comple();
+
+		} break;
+		case EDIT_AUTO_INDENT: {
+
+			TextEdit *te = code_editor->get_text_edit();
+			String text = te->get_text();
+			Ref<Script> scr = get_edited_script();
+			if (scr.is_null())
+				return;
+			int begin,end;
+			if (te->is_selection_active()) {
+				begin=te->get_selection_from_line();
+				end=te->get_selection_to_line();
+			} else {
+				begin=0;
+				end=te->get_line_count()-1;
+			}
+			scr->get_language()->auto_indent_code(text,begin,end);
+			te->set_text(text);
+
+
+		} break;
+		case EDIT_TRIM_TRAILING_WHITESAPCE: {
+			trim_trailing_whitespace();
+		} break;
+
+
+		case SEARCH_FIND: {
+
+			code_editor->get_find_replace_bar()->popup_search();
+		} break;
+		case SEARCH_FIND_NEXT: {
+
+			code_editor->get_find_replace_bar()->search_next();
+		} break;
+		case SEARCH_FIND_PREV: {
+
+			code_editor->get_find_replace_bar()->search_prev();
+		} break;
+		case SEARCH_REPLACE: {
+
+			code_editor->get_find_replace_bar()->popup_replace();
+		} break;
+		case SEARCH_LOCATE_FUNCTION: {
+
+			quick_open->popup(get_functions());
+		} break;
+		case SEARCH_GOTO_LINE: {
+
+			goto_line_dialog->popup_find_line(code_editor->get_text_edit());
+		} break;
+		case DEBUG_TOGGLE_BREAKPOINT: {
+			int line=code_editor->get_text_edit()->cursor_get_line();
+			bool dobreak = !code_editor->get_text_edit()->is_line_set_as_breakpoint(line);
+			code_editor->get_text_edit()->set_line_as_breakpoint(line,dobreak);
+			ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(get_edited_script()->get_path(),line+1,dobreak);
+		} break;
+		case DEBUG_REMOVE_ALL_BREAKPOINTS: {
+			List<int> bpoints;
+			code_editor->get_text_edit()->get_breakpoints(&bpoints);
+
+			for(List<int>::Element *E=bpoints.front();E;E=E->next()) {
+				int line = E->get();
+				bool dobreak = !code_editor->get_text_edit()->is_line_set_as_breakpoint(line);
+				code_editor->get_text_edit()->set_line_as_breakpoint(line,dobreak);
+				ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(get_edited_script()->get_path(),line+1,dobreak);
+			}
+		}
+		case DEBUG_GOTO_NEXT_BREAKPOINT: {
+			List<int> bpoints;
+			code_editor->get_text_edit()->get_breakpoints(&bpoints);
+			if (bpoints.size() <= 0) {
+				return;
+			}
+
+			int line=code_editor->get_text_edit()->cursor_get_line();
+			// wrap around
+			if (line >= bpoints[bpoints.size() - 1]) {
+				code_editor->get_text_edit()->cursor_set_line(bpoints[0]);
+			} else {
+				for(List<int>::Element *E=bpoints.front();E;E=E->next()) {
+					int bline = E->get();
+					if (bline > line) {
+						code_editor->get_text_edit()->cursor_set_line(bline);
+						return;
+					}
+				}
+			}
+
+		} break;
+		case DEBUG_GOTO_PREV_BREAKPOINT: {
+			List<int> bpoints;
+			code_editor->get_text_edit()->get_breakpoints(&bpoints);
+			if (bpoints.size() <= 0) {
+				return;
+			}
+
+			int line=code_editor->get_text_edit()->cursor_get_line();
+			// wrap around
+			if (line <= bpoints[0]) {
+				code_editor->get_text_edit()->cursor_set_line(bpoints[bpoints.size() - 1]);
+			} else {
+				for(List<int>::Element *E=bpoints.back();E;E=E->prev()) {
+					int bline = E->get();
+					if (bline < line) {
+						code_editor->get_text_edit()->cursor_set_line(bline);
+						return;
+					}
+				}
+			}
+
+		} break;
+
+		case HELP_CONTEXTUAL: {
+			String text = code_editor->get_text_edit()->get_selection_text();
+			if (text == "")
+				text = code_editor->get_text_edit()->get_word_under_cursor();
+			if (text != "") {
+				emit_signal("request_help_search",text);
+			}
+		} break;
+	}
+}
+
+void ScriptTextEditor::_bind_methods() {
+
+	ObjectTypeDB::bind_method("_validate_script",&ScriptTextEditor::_validate_script);
+	ObjectTypeDB::bind_method("_load_theme_settings",&ScriptTextEditor::_load_theme_settings);
+	ObjectTypeDB::bind_method("_breakpoint_toggled",&ScriptTextEditor::_breakpoint_toggled);
+	ObjectTypeDB::bind_method("_edit_option",&ScriptTextEditor::_edit_option);
+	ObjectTypeDB::bind_method("_goto_line",&ScriptTextEditor::_goto_line);
+
+	ADD_SIGNAL(MethodInfo("name_changed"));
+	ADD_SIGNAL(MethodInfo("request_help_search",PropertyInfo(Variant::STRING,"topic")));
+}
+
+Control *ScriptTextEditor::get_edit_menu() {
+
+	return edit_hb;
+}
+
+void ScriptTextEditor::reload(bool p_soft) {
+
+	TextEdit *te = code_editor->get_text_edit();
+	Ref<Script> scr = get_edited_script();
+	if (scr.is_null())
+		return;
+	scr->set_source_code(te->get_text());
+	bool soft =  p_soft || scr->get_instance_base_type()=="EditorPlugin"; //always soft-reload editor plugins
+
+	scr->get_language()->reload_tool_script(scr,soft);
+}
+
+void ScriptTextEditor::get_breakpoints(List<int> *p_breakpoints) {
+
+	code_editor->get_text_edit()->get_breakpoints(p_breakpoints);
+
+}
+
+void ScriptTextEditor::set_tooltip_request_func(String p_method,Object* p_obj) {
+
+	code_editor->get_text_edit()->set_tooltip_request_func(p_obj,p_method,this);
+}
+
+ScriptTextEditor::ScriptTextEditor() {
+
+	code_editor = memnew( CodeTextEditor );
+	add_child(code_editor);
+	code_editor->set_area_as_parent_rect();
+	code_editor->connect("validate_script",this,"_validate_script");
+	code_editor->connect("load_theme_settings",this,"_load_theme_settings");
+	code_editor->set_code_complete_func(_code_complete_scripts,this);
+	code_editor->get_text_edit()->connect("breakpoint_toggled", this, "_breakpoint_toggled");
+
+	code_editor->get_text_edit()->set_scroll_pass_end_of_file(EditorSettings::get_singleton()->get("text_editor/scroll_past_end_of_file"));
+	code_editor->get_text_edit()->set_auto_brace_completion(EditorSettings::get_singleton()->get("text_editor/auto_brace_complete"));
+	code_editor->get_text_edit()->set_tab_size(EditorSettings::get_singleton()->get("text_editor/tab_size"));
+	code_editor->get_text_edit()->set_draw_tabs(EditorSettings::get_singleton()->get("text_editor/draw_tabs"));
+	code_editor->get_text_edit()->set_show_line_numbers(EditorSettings::get_singleton()->get("text_editor/show_line_numbers"));
+	code_editor->get_text_edit()->set_syntax_coloring(EditorSettings::get_singleton()->get("text_editor/syntax_highlighting"));
+	code_editor->get_text_edit()->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/highlight_all_occurrences"));
+	code_editor->get_text_edit()->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/caret_blink"));
+	code_editor->get_text_edit()->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/caret_blink_speed"));
+	code_editor->get_text_edit()->set_draw_breakpoint_gutter(EditorSettings::get_singleton()->get("text_editor/show_breakpoint_gutter"));
+	code_editor->get_text_edit()->cursor_set_block_mode(EditorSettings::get_singleton()->get("text_editor/block_caret"));
+	code_editor->get_text_edit()->set_callhint_settings(
+		EditorSettings::get_singleton()->get("text_editor/put_callhint_tooltip_below_current_line"),
+		EditorSettings::get_singleton()->get("text_editor/callhint_tooltip_offset"));
+
+	edit_hb = memnew (HBoxContainer);
+
+	edit_menu = memnew( MenuButton );
+	edit_menu->set_text(TTR("Edit"));
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO);
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/redo"), EDIT_REDO);
+	edit_menu->get_popup()->add_separator();
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/cut"), EDIT_CUT);
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/copy"), EDIT_COPY);
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/paste"), EDIT_PASTE);
+	edit_menu->get_popup()->add_separator();
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/select_all"), EDIT_SELECT_ALL);
+	edit_menu->get_popup()->add_separator();
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_up"), EDIT_MOVE_LINE_UP);
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_down"), EDIT_MOVE_LINE_DOWN);
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_left"), EDIT_INDENT_LEFT);
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_right"), EDIT_INDENT_RIGHT);
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT);
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/clone_down"), EDIT_CLONE_DOWN);
+	edit_menu->get_popup()->add_separator();
+#ifdef OSX_ENABLED
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/complete_symbol"), EDIT_COMPLETE);
+#else
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/complete_symbol"), EDIT_COMPLETE);
+#endif
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/trim_trailing_whitespace"), EDIT_TRIM_TRAILING_WHITESAPCE);
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/auto_indent"), EDIT_AUTO_INDENT);
+	edit_menu->get_popup()->connect("item_pressed", this,"_edit_option");
+	edit_menu->get_popup()->add_separator();
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_breakpoint"), DEBUG_TOGGLE_BREAKPOINT);
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/remove_all_breakpoints"), DEBUG_REMOVE_ALL_BREAKPOINTS);
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_breakpoint"), DEBUG_GOTO_NEXT_BREAKPOINT);
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_breakpoint"), DEBUG_GOTO_PREV_BREAKPOINT);
+
+	search_menu = memnew( MenuButton );
+	edit_hb->add_child(search_menu);
+	search_menu->set_text(TTR("Search"));
+	search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND);
+	search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_next"), SEARCH_FIND_NEXT);
+	search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_previous"), SEARCH_FIND_PREV);
+	search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace"), SEARCH_REPLACE);
+	search_menu->get_popup()->add_separator();
+	search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_function"), SEARCH_LOCATE_FUNCTION);
+	search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_line"), SEARCH_GOTO_LINE);
+	search_menu->get_popup()->add_separator();
+	search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/contextual_help"), HELP_CONTEXTUAL);
+
+	search_menu->get_popup()->connect("item_pressed", this,"_edit_option");
+
+	edit_hb->add_child(edit_menu);
+
+	quick_open = memnew( ScriptEditorQuickOpen );
+	add_child(quick_open);
+	quick_open->connect("goto_line",this,"_goto_line");
+
+	goto_line_dialog = memnew(GotoLineDialog);
+	add_child(goto_line_dialog);
+}
+
+static ScriptEditorBase * create_editor(const Ref<Script>& p_script) {
+
+	if (p_script->has_source_code()) {
+		return memnew( ScriptTextEditor );
+	}
+
+	return NULL;
+}
+
+void ScriptTextEditor::register_editor() {
+
+	ED_SHORTCUT("script_text_editor/undo", TTR("Undo"), KEY_MASK_CMD|KEY_Z);
+	ED_SHORTCUT("script_text_editor/redo", TTR("Redo"), KEY_MASK_CMD|KEY_Y);
+	ED_SHORTCUT("script_text_editor/cut", TTR("Cut"), KEY_MASK_CMD|KEY_X);
+	ED_SHORTCUT("script_text_editor/copy", TTR("Copy"), KEY_MASK_CMD|KEY_C);
+	ED_SHORTCUT("script_text_editor/paste", TTR("Paste"), KEY_MASK_CMD|KEY_V);
+	ED_SHORTCUT("script_text_editor/select_all", TTR("Select All"), KEY_MASK_CMD|KEY_A);
+	ED_SHORTCUT("script_text_editor/move_up", TTR("Move Up"), KEY_MASK_ALT|KEY_UP);
+	ED_SHORTCUT("script_text_editor/move_down", TTR("Move Down"), KEY_MASK_ALT|KEY_DOWN);
+	ED_SHORTCUT("script_text_editor/indent_left", TTR("Indent Left"), KEY_MASK_ALT|KEY_LEFT);
+	ED_SHORTCUT("script_text_editor/indent_right", TTR("Indent Right"), KEY_MASK_ALT|KEY_RIGHT);
+	ED_SHORTCUT("script_text_editor/toggle_comment", TTR("Toggle Comment"), KEY_MASK_CMD|KEY_K);
+	ED_SHORTCUT("script_text_editor/clone_down", TTR("Clone Down"), KEY_MASK_CMD|KEY_B);
+#ifdef OSX_ENABLED
+	ED_SHORTCUT("script_text_editor/complete_symbol", TTR("Complete Symbol"), KEY_MASK_CTRL|KEY_SPACE);
+#else
+	ED_SHORTCUT("script_text_editor/complete_symbol", TTR("Complete Symbol"), KEY_MASK_CMD|KEY_SPACE);
+#endif
+	ED_SHORTCUT("script_text_editor/trim_trailing_whitespace", TTR("Trim Trailing Whitespace"), KEY_MASK_CTRL|KEY_MASK_ALT|KEY_T);
+	ED_SHORTCUT("script_text_editor/auto_indent", TTR("Auto Indent"), KEY_MASK_CMD|KEY_I);
+
+	ED_SHORTCUT("script_text_editor/toggle_breakpoint", TTR("Toggle Breakpoint"), KEY_F9);
+	ED_SHORTCUT("script_text_editor/remove_all_breakpoints", TTR("Remove All Breakpoints"), KEY_MASK_CTRL|KEY_MASK_SHIFT|KEY_F9);
+	ED_SHORTCUT("script_text_editor/goto_next_breakpoint", TTR("Goto Next Breakpoint"), KEY_MASK_CTRL|KEY_PERIOD);
+	ED_SHORTCUT("script_text_editor/goto_previous_breakpoint", TTR("Goto Previous Breakpoint"), KEY_MASK_CTRL|KEY_COMMA);
+
+	ED_SHORTCUT("script_text_editor/find", TTR("Find.."), KEY_MASK_CMD|KEY_F);
+	ED_SHORTCUT("script_text_editor/find_next", TTR("Find Next"), KEY_F3);
+	ED_SHORTCUT("script_text_editor/find_previous", TTR("Find Previous"), KEY_MASK_SHIFT|KEY_F3);
+	ED_SHORTCUT("script_text_editor/replace", TTR("Replace.."), KEY_MASK_CMD|KEY_R);
+
+	ED_SHORTCUT("script_text_editor/goto_function", TTR("Goto Function.."), KEY_MASK_SHIFT|KEY_MASK_CMD|KEY_F);
+	ED_SHORTCUT("script_text_editor/goto_line", TTR("Goto Line.."), KEY_MASK_CMD|KEY_L);
+
+	ED_SHORTCUT("script_text_editor/contextual_help", TTR("Contextual Help"), KEY_MASK_SHIFT|KEY_F1);
+
+	ScriptEditor::register_create_script_editor_function(create_editor);
+}

+ 112 - 0
tools/editor/plugins/script_text_editor.h

@@ -0,0 +1,112 @@
+#ifndef SCRIPT_TEXT_EDITOR_H
+#define SCRIPT_TEXT_EDITOR_H
+
+#include "script_editor_plugin.h"
+
+
+class ScriptTextEditor : public ScriptEditorBase {
+
+	OBJ_TYPE( ScriptTextEditor, ScriptEditorBase );
+
+	CodeTextEditor *code_editor;
+
+	Ref<Script> script;
+
+
+	Vector<String> functions;
+
+	HBoxContainer *edit_hb;
+
+	MenuButton *edit_menu;
+	MenuButton *search_menu;
+
+	GotoLineDialog *goto_line_dialog;
+	ScriptEditorQuickOpen *quick_open;
+
+	enum {
+		EDIT_UNDO,
+		EDIT_REDO,
+		EDIT_CUT,
+		EDIT_COPY,
+		EDIT_PASTE,
+		EDIT_SELECT_ALL,
+		EDIT_COMPLETE,
+		EDIT_AUTO_INDENT,
+		EDIT_TRIM_TRAILING_WHITESAPCE,
+		EDIT_TOGGLE_COMMENT,
+		EDIT_MOVE_LINE_UP,
+		EDIT_MOVE_LINE_DOWN,
+		EDIT_INDENT_RIGHT,
+		EDIT_INDENT_LEFT,
+		EDIT_CLONE_DOWN,
+		SEARCH_FIND,
+		SEARCH_FIND_NEXT,
+		SEARCH_FIND_PREV,
+		SEARCH_REPLACE,
+		SEARCH_LOCATE_FUNCTION,
+		SEARCH_GOTO_LINE,
+		DEBUG_TOGGLE_BREAKPOINT,
+		DEBUG_REMOVE_ALL_BREAKPOINTS,
+		DEBUG_GOTO_NEXT_BREAKPOINT,
+		DEBUG_GOTO_PREV_BREAKPOINT,
+		HELP_CONTEXTUAL,
+	};
+
+
+protected:
+
+
+	static void _code_complete_scripts(void* p_ud,const String& p_code, List<String>* r_options);
+	void _breakpoint_toggled(int p_row);
+
+	//no longer virtual
+	void _validate_script();
+	void _code_complete_script(const String& p_code, List<String>* r_options);
+	void _load_theme_settings();
+
+	void _notification(int p_what);
+	static void _bind_methods();
+
+	void _edit_option(int p_op);
+
+	void _goto_line(int p_line) { goto_line(p_line); }
+public:
+
+	virtual void apply_code();
+	virtual Ref<Script> get_edited_script() const;
+	virtual Vector<String> get_functions() ;
+	virtual void set_edited_script(const Ref<Script>& p_script);
+	virtual void reload_text();
+	virtual String get_name() ;
+	virtual Ref<Texture> get_icon() ;
+	virtual bool is_unsaved();
+
+	virtual Variant get_edit_state();
+	virtual void set_edit_state(const Variant& p_state);
+	virtual void ensure_focus();
+	virtual void trim_trailing_whitespace();
+	virtual void tag_saved_version();
+
+	virtual void goto_line(int p_line);
+
+	virtual void reload(bool p_soft);
+	virtual void get_breakpoints(List<int> *p_breakpoints);
+
+	virtual void add_callback(const String& p_function,StringArray p_args);
+	virtual void update_settings();
+	virtual bool goto_method(const String& p_method);
+
+	virtual void set_tooltip_request_func(String p_method,Object* p_obj);
+
+	Control *get_edit_menu();
+
+	static void register_editor();
+
+	ScriptTextEditor();
+
+};
+
+
+
+
+#endif // SCRIPT_TEXT_EDITOR_H

+ 24 - 4
tools/editor/property_editor.cpp

@@ -940,11 +940,23 @@ void CustomPropertyEditor::_color_changed(const Color& p_color) {
 
 
 void CustomPropertyEditor::_node_path_selected(NodePath p_path) {
 void CustomPropertyEditor::_node_path_selected(NodePath p_path) {
 
 
-	if (owner) {
+
+	if (hint==PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE && hint_text!=String()) {
+
+		Node* node=get_node(hint_text);
+		if (node) {
+
+			Node *tonode=node->get_node(p_path);
+			if (tonode) {
+				p_path=node->get_path_to(tonode);
+			}
+		}
+
+	} else if (owner) {
 
 
 		Node *node=NULL;
 		Node *node=NULL;
 
 
-		if (owner->is_type("Node"))
+		 if (owner->is_type("Node"))
 			node = owner->cast_to<Node>();
 			node = owner->cast_to<Node>();
 		else if (owner->is_type("ArrayPropertyEdit"))
 		else if (owner->is_type("ArrayPropertyEdit"))
 			node = owner->cast_to<ArrayPropertyEdit>()->get_node();
 			node = owner->cast_to<ArrayPropertyEdit>()->get_node();
@@ -4349,7 +4361,7 @@ SectionedPropertyEditor::~SectionedPropertyEditor() {
 
 
 double PropertyValueEvaluator::eval(const String& p_text) {
 double PropertyValueEvaluator::eval(const String& p_text) {
 
 
-	if (!obj)
+	if (!obj || !script_language)
 		return _default_eval(p_text);
 		return _default_eval(p_text);
 
 
 	Ref<Script> script= Ref<Script>(script_language ->create_script());
 	Ref<Script> script= Ref<Script>(script_language ->create_script());
@@ -4361,6 +4373,8 @@ double PropertyValueEvaluator::eval(const String& p_text) {
 	}
 	}
 
 
 	ScriptInstance *script_instance = script->instance_create(this);
 	ScriptInstance *script_instance = script->instance_create(this);
+	if (!script_instance)
+		return _default_eval(p_text);
 
 
 	Variant::CallError call_err;
 	Variant::CallError call_err;
 	script_instance->call("set_this",obj);
 	script_instance->call("set_this",obj);
@@ -4388,7 +4402,13 @@ String PropertyValueEvaluator::_build_script(const String& p_text) {
 }
 }
 
 
 PropertyValueEvaluator::PropertyValueEvaluator() {
 PropertyValueEvaluator::PropertyValueEvaluator() {
-	script_language = ScriptServer::get_language(0); // todo: get script language from editor setting
+	script_language=NULL;
+
+	for(int i=0;i<ScriptServer::get_language_count();i++) {
+		if (ScriptServer::get_language(i)->get_name()=="GDScript") {
+			script_language=ScriptServer::get_language(i);
+		}
+	}
 }
 }
 
 
 PropertyValueEvaluator::~PropertyValueEvaluator() {
 PropertyValueEvaluator::~PropertyValueEvaluator() {

部分文件因为文件数量过多而无法显示