Browse Source

More visual script work
-Block switches to 2d/3d editor if editing visual script
-Added cast node in flow control
-Added ability to do RPC in visual script
-Comment nodes
-Fix bug with inverted cable in connecting backwards
-Copy and paste nodes, including from different scripts

Juan Linietsky 9 years ago
parent
commit
9c6175db11
35 changed files with 1635 additions and 247 deletions
  1. 92 29
      core/object.cpp
  2. 8 0
      core/object.h
  3. 1 1
      core/object_type_db.cpp
  4. 1 0
      core/script_language.cpp
  5. 6 0
      core/script_language.h
  6. 9 0
      modules/gdscript/gd_script.cpp
  7. 2 0
      modules/gdscript/gd_script.h
  8. 5 3
      modules/visual_script/register_types.cpp
  9. 49 18
      modules/visual_script/visual_script.cpp
  10. 3 0
      modules/visual_script/visual_script.h
  11. 204 1
      modules/visual_script/visual_script_editor.cpp
  12. 14 0
      modules/visual_script/visual_script_editor.h
  13. 193 0
      modules/visual_script/visual_script_flow_control.cpp
  14. 47 0
      modules/visual_script/visual_script_flow_control.h
  15. 567 179
      modules/visual_script/visual_script_func_nodes.cpp
  16. 48 2
      modules/visual_script/visual_script_func_nodes.h
  17. 171 0
      modules/visual_script/visual_script_nodes.cpp
  18. 49 0
      modules/visual_script/visual_script_nodes.h
  19. 9 6
      modules/visual_script/visual_script_yield_nodes.cpp
  20. 1 0
      modules/visual_script/visual_script_yield_nodes.h
  21. 8 1
      scene/gui/control.cpp
  22. 6 0
      scene/gui/control.h
  23. 12 0
      scene/gui/graph_edit.cpp
  24. 2 0
      scene/gui/graph_edit.h
  25. 74 3
      scene/gui/graph_node.cpp
  26. 14 0
      scene/gui/graph_node.h
  27. 3 0
      scene/resources/default_theme/default_theme.cpp
  28. BIN
      scene/resources/default_theme/graph_node_comment.png
  29. 1 0
      scene/resources/default_theme/theme_data.h
  30. BIN
      scene/resources/default_theme/window_resizer.png
  31. 1 1
      tools/editor/editor_node.cpp
  32. 27 2
      tools/editor/plugins/script_editor_plugin.cpp
  33. 6 1
      tools/editor/plugins/script_editor_plugin.h
  34. 1 0
      tools/editor/property_editor.cpp
  35. 1 0
      tools/editor/property_selector.cpp

+ 92 - 29
core/object.cpp

@@ -59,30 +59,112 @@ struct _ObjectDebugLock {
 
 #endif
 
+
+PropertyInfo::operator Dictionary() const {
+
+	Dictionary d;
+	d["name"]=name;
+	d["type"]=type;
+	d["hint"]=hint;
+	d["hint_string"]=hint_string;
+	d["usage"]=usage;
+	return d;
+
+}
+
+PropertyInfo PropertyInfo::from_dict(const Dictionary& p_dict) {
+
+	PropertyInfo pi;
+
+	if (p_dict.has("type"))
+		pi.type=Variant::Type(int(p_dict["type"]));
+
+	if (p_dict.has("name"))
+		pi.name=p_dict["name"];
+
+	if (p_dict.has("hint"))
+		pi.hint=PropertyHint(int(p_dict["hint"]));
+
+	if (p_dict.has("hint_string"))
+
+		pi.hint_string=p_dict["hint_string"];
+
+	if (p_dict.has("usage"))
+		pi.usage=p_dict["usage"];
+
+	return pi;
+}
+
+
 Array convert_property_list(const List<PropertyInfo> * p_list) {
 
 	Array va;
 	for (const List<PropertyInfo>::Element *E=p_list->front();E;E=E->next()) {
 
-		const PropertyInfo &pi = E->get();
-		Dictionary d;
-		d["name"]=pi.name;
-		d["type"]=pi.type;
-		d["hint"]=pi.hint;
-		d["hint_string"]=pi.hint_string;
-		d["usage"]=pi.usage;
-		va.push_back(d);
+
+		va.push_back(Dictionary(E->get()));
 	}
 
 	return va;
 }
 
+MethodInfo::operator Dictionary() const {
+
+
+	Dictionary d;
+	d["name"]=name;
+	d["args"]=convert_property_list(&arguments);
+	Array da;
+	for(int i=0;i<default_arguments.size();i++)
+		da.push_back(default_arguments[i]);
+	d["default_args"]=da;
+	d["flags"]=flags;
+	d["id"]=id;
+	Dictionary r = return_val;
+	d["return"]=r;
+	return d;
+
+}
+
 MethodInfo::MethodInfo() {
 
 	id=0;
 	flags=METHOD_FLAG_NORMAL;
 }
 
+MethodInfo MethodInfo::from_dict(const Dictionary& p_dict) {
+
+	MethodInfo mi;
+
+	if (p_dict.has("name"))
+		mi.name=p_dict["name"];
+	Array args;
+	if (p_dict.has("args")) {
+		args=p_dict["args"];
+	}
+
+	for(int i=0;i<args.size();i++) {
+		Dictionary d = args[i];
+		mi.arguments.push_back(PropertyInfo::from_dict(d));
+	}
+	Array defargs;
+	if (p_dict.has("default_args")) {
+		defargs=p_dict["default_args"];
+	}
+	for(int i=0;i<defargs.size();i++) {
+		mi.default_arguments.push_back(defargs[i]);
+	}
+
+	if (p_dict.has("return")) {
+		mi.return_val=PropertyInfo::from_dict(p_dict["return"]);
+	}
+
+	if (p_dict.has("flags"))
+		mi.flags=p_dict["flags"];
+
+	return mi;
+}
+
 MethodInfo::MethodInfo(const String& p_name) {
 
 	id=0;
@@ -1012,25 +1094,6 @@ Array Object::_get_property_list_bind() const {
 }
 
 
-static Dictionary _get_dict_from_method(const MethodInfo &mi) {
-
-	Dictionary d;
-	d["name"]=mi.name;
-	d["args"]=convert_property_list(&mi.arguments);
-	Array da;
-	for(int i=0;i<mi.default_arguments.size();i++)
-		da.push_back(mi.default_arguments[i]);
-	d["default_args"]=da;
-	d["flags"]=mi.flags;
-	d["id"]=mi.id;
-	Dictionary r;
-	r["type"]=mi.return_val.type;
-	r["hint"]=mi.return_val.hint;
-	r["hint_string"]=mi.return_val.hint_string;
-	d["return_type"]=r;
-	return d;
-
-}
 
 Array Object::_get_method_list_bind() const {
 
@@ -1040,7 +1103,7 @@ Array Object::_get_method_list_bind() const {
 
 	for(List<MethodInfo>::Element *E=ml.front();E;E=E->next()) {
 
-		Dictionary d = _get_dict_from_method(E->get());
+		Dictionary d = E->get();
 		//va.push_back(d);
 		ret.push_back(d);
 	}
@@ -1305,7 +1368,7 @@ Array Object::_get_signal_list() const{
 	Array ret;
 	for (List<MethodInfo>::Element *E=signal_list.front();E;E=E->next()) {
 
-		ret.push_back(_get_dict_from_method(E->get()));
+		ret.push_back(Dictionary(E->get()));
 	}
 
 	return ret;

+ 8 - 0
core/object.h

@@ -126,6 +126,11 @@ struct PropertyInfo {
 
 	_FORCE_INLINE_ PropertyInfo added_usage(int p_fl) const { PropertyInfo pi=*this; pi.usage|=p_fl; return pi; }
 
+
+	operator Dictionary() const;
+
+	static PropertyInfo from_dict(const Dictionary& p_dict);
+
 	PropertyInfo() { type=Variant::NIL; hint=PROPERTY_HINT_NONE; usage = PROPERTY_USAGE_DEFAULT; }
 	PropertyInfo( Variant::Type p_type, const String p_name, PropertyHint p_hint=PROPERTY_HINT_NONE, const String& p_hint_string="",uint32_t p_usage=PROPERTY_USAGE_DEFAULT) {
 		type=p_type; name=p_name; hint=p_hint; hint_string=p_hint_string; usage=p_usage;
@@ -150,6 +155,9 @@ struct MethodInfo {
 
 	inline bool  operator<(const MethodInfo& p_method) const { return id==p_method.id?(name < p_method.name):(id<p_method.id); }
 
+	operator Dictionary() const;
+
+	static MethodInfo from_dict(const Dictionary& p_dict);
 	MethodInfo();
 	MethodInfo(const String& p_name);
 	MethodInfo(const String& p_name, const PropertyInfo& p_param1);

+ 1 - 1
core/object_type_db.cpp

@@ -642,7 +642,7 @@ void ObjectTypeDB::get_property_list(StringName p_type, List<PropertyInfo> *p_li
 	TypeInfo *check=type;
 	while(check) {
 
-		for(List<PropertyInfo>::Element *E=type->property_list.front();E;E=E->next()) {
+		for(List<PropertyInfo>::Element *E=check->property_list.front();E;E=E->next()) {
 
 
 			if (p_validator) {

+ 1 - 0
core/script_language.cpp

@@ -33,6 +33,7 @@ int ScriptServer::_language_count=0;
 
 bool ScriptServer::scripting_enabled=true;
 bool ScriptServer::reload_scripts_on_save=false;
+ScriptEditRequestFunction ScriptServer::edit_request_func=NULL;
 
 void Script::_notification( int p_what) {
 

+ 6 - 0
core/script_language.h

@@ -38,6 +38,8 @@
 
 class ScriptLanguage;
 
+typedef void (*ScriptEditRequestFunction)(const String& p_path);
+
 class ScriptServer {
 	enum {
 
@@ -50,6 +52,8 @@ class ScriptServer {
 	static bool reload_scripts_on_save;
 public:
 
+	static ScriptEditRequestFunction edit_request_func;
+
 	static void set_scripting_enabled(bool p_enabled);
 	static bool is_scripting_enabled();
 	static int get_language_count();
@@ -88,6 +92,8 @@ public:
 
 	virtual bool can_instance() const=0;
 
+	virtual Ref<Script> get_base_script() const=0; //for script inheritance
+
 	virtual StringName get_instance_base_type() const=0; // this may not work in all scripts, will return empty if so
 	virtual ScriptInstance* instance_create(Object *p_this)=0;
 	virtual bool instance_has(const Object *p_this) const=0;

+ 9 - 0
modules/gdscript/gd_script.cpp

@@ -179,6 +179,15 @@ bool GDScript::can_instance() const {
 
 }
 
+Ref<Script> GDScript::get_base_script() const {
+
+	if (_base) {
+		return Ref<GDScript>( _base );
+	} else {
+		return Ref<Script>();
+	}
+}
+
 StringName GDScript::get_instance_base_type() const {
 
 	if (native.is_valid())

+ 2 - 0
modules/gdscript/gd_script.h

@@ -162,6 +162,8 @@ public:
 	Variant _new(const Variant** p_args,int p_argcount,Variant::CallError& r_error);
 	virtual bool can_instance() const;
 
+	virtual Ref<Script> get_base_script() const;
+
 	virtual StringName get_instance_base_type() const; // this may not work in all scripts, will return empty if so
 	virtual ScriptInstance* instance_create(Object *p_this);
 	virtual bool instance_has(const Object *p_this) const;

+ 5 - 3
modules/visual_script/register_types.cpp

@@ -43,6 +43,10 @@ VisualScriptLanguage *visual_script_language=NULL;
 
 void register_visual_script_types() {
 
+	visual_script_language=memnew( VisualScriptLanguage );
+	//script_language_gd->init();
+	ScriptServer::register_language(visual_script_language);
+
 	ObjectTypeDB::register_type<VisualScript>();
 	ObjectTypeDB::register_virtual_type<VisualScriptNode>();
 	ObjectTypeDB::register_virtual_type<VisualScriptFunctionState>();
@@ -62,6 +66,7 @@ void register_visual_script_types() {
 	ObjectTypeDB::register_type<VisualScriptSelf>();
 	ObjectTypeDB::register_type<VisualScriptCustomNode>();
 	ObjectTypeDB::register_type<VisualScriptSubCall>();
+	ObjectTypeDB::register_type<VisualScriptComment>();
 
 	ObjectTypeDB::register_type<VisualScriptFunctionCall>();
 	ObjectTypeDB::register_type<VisualScriptPropertySet>();
@@ -82,9 +87,6 @@ void register_visual_script_types() {
 
 	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();

+ 49 - 18
modules/visual_script/visual_script.cpp

@@ -1,7 +1,7 @@
 #include "visual_script.h"
 #include "visual_script_nodes.h"
 #include "scene/main/node.h"
-
+#include "os/os.h"
 #include "globals.h"
 #define SCRIPT_VARIABLES_PREFIX "script_variables/"
 
@@ -31,11 +31,13 @@ void VisualScriptNode::_notification(int p_what) {
 
 void VisualScriptNode::ports_changed_notify(){
 
+
 	default_input_values.resize( MAX(default_input_values.size(),get_input_value_port_count()) ); //let it grow as big as possible, we don't want to lose values on resize
+
 	emit_signal("ports_changed");
 }
 
-void  VisualScriptNode::set_default_input_value(int p_port,const Variant& p_value) {
+void VisualScriptNode::set_default_input_value(int p_port,const Variant& p_value) {
 
 	ERR_FAIL_INDEX(p_port,default_input_values.size());
 
@@ -54,35 +56,40 @@ void VisualScriptNode::_set_default_input_values(Array p_values) {
 	default_input_values=p_values;
 }
 
-Array VisualScriptNode::_get_default_input_values() const {
 
-	//validate on save, since on load there is little info about this
+void VisualScriptNode::validate_input_default_values() {
+
 
-	Array saved_values;
+
+	default_input_values.resize(get_input_value_port_count());
 
 	//actually validate on save
 	for(int i=0;i<get_input_value_port_count();i++) {
 
 		Variant::Type expected = get_input_value_port_info(i).type;
 
-		if (i>=default_input_values.size()) {
 
+		if (expected==Variant::NIL || expected==default_input_values[i].get_type()) {
+			continue;
+		} else  {
+			//not the same, reconvert
 			Variant::CallError ce;
-			saved_values.push_back(Variant::construct(expected,NULL,0,ce,false));
-		} else {
-
-			if (expected==Variant::NIL || expected==default_input_values[i].get_type()) {
-				saved_values.push_back(default_input_values[i]);
-			} else  {
-				//not the same, reconvert
-				Variant::CallError ce;
-				Variant existing = default_input_values[i];
-				const Variant *existingp=&existing;
-				saved_values.push_back( Variant::construct(expected,&existingp,1,ce,false) );
+			Variant existing = default_input_values[i];
+			const Variant *existingp=&existing;
+			default_input_values[i] = Variant::construct(expected,&existingp,1,ce,false);
+			if (ce.error!=Variant::CallError::CALL_OK) {
+				//could not convert? force..
+				default_input_values[i] = Variant::construct(expected,NULL,0,ce,false);
 			}
 		}
 	}
-	return saved_values;
+}
+
+Array VisualScriptNode::_get_default_input_values() const {
+
+	//validate on save, since on load there is little info about this
+
+	return default_input_values;
 }
 
 
@@ -224,6 +231,7 @@ int VisualScript::get_function_node_id(const StringName& p_name) const {
 void VisualScript::_node_ports_changed(int p_id) {
 
 
+
 	StringName function;
 
 	for (Map<StringName,Function>::Element *E=functions.front();E;E=E->next()) {
@@ -239,6 +247,10 @@ void VisualScript::_node_ports_changed(int p_id) {
 	Function &func = functions[function];
 	Ref<VisualScriptNode> vsn = func.nodes[p_id].node;
 
+	if (OS::get_singleton()->get_main_loop() && OS::get_singleton()->get_main_loop()->cast_to<SceneTree>() && OS::get_singleton()->get_main_loop()->cast_to<SceneTree>()->is_editor_hint()) {
+		vsn->validate_input_default_values(); //force validate default values when editing on editor
+	}
+
 	//must revalidate all the functions
 
 	{
@@ -836,6 +848,10 @@ StringName VisualScript::get_instance_base_type() const {
 	return base_type;
 }
 
+Ref<Script> VisualScript::get_base_script() const {
+	return Ref<Script>(); // no inheritance in visual script
+}
+
 
 #ifdef TOOLS_ENABLED
 void VisualScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) {
@@ -1884,8 +1900,23 @@ Ref<Script> VisualScriptInstance::get_script() const{
 
 ScriptInstance::RPCMode VisualScriptInstance::get_rpc_mode(const StringName& p_method) const {
 
+	const Map<StringName,VisualScript::Function>::Element *E = script->functions.find(p_method);
+	if (!E) {
+		return RPC_MODE_DISABLED;
+	}
+
+	if (E->get().function_id>=0 && E->get().nodes.has(E->get().function_id)) {
+
+		Ref<VisualScriptFunction> vsf = E->get().nodes[E->get().function_id].node;
+		if (vsf.is_valid()) {
+
+			return vsf->get_rpc_mode();
+		}
+	}
+
 	return RPC_MODE_DISABLED;
 }
+
 ScriptInstance::RPCMode VisualScriptInstance::get_rset_mode(const StringName& p_variable) const {
 
 	return RPC_MODE_DISABLED;

+ 3 - 0
modules/visual_script/visual_script.h

@@ -20,6 +20,8 @@ friend class VisualScript;
 
 	void _set_default_input_values(Array p_values);
 	Array _get_default_input_values() const;
+
+	void validate_input_default_values();
 protected:
 
 	virtual bool _use_builtin_script() const { return false; }
@@ -300,6 +302,7 @@ public:
 
 	virtual bool can_instance() const;
 
+	virtual Ref<Script> get_base_script() const;
 	virtual StringName get_instance_base_type() const;
 	virtual ScriptInstance* instance_create(Object *p_this);
 	virtual bool instance_has(const Object *p_this) const;

+ 204 - 1
modules/visual_script/visual_script_editor.cpp

@@ -347,6 +347,8 @@ void VisualScriptEditor::_update_graph_connections() {
 
 void VisualScriptEditor::_update_graph(int p_only_id) {
 
+	if (updating_graph)
+		return;
 
 	updating_graph=true;
 
@@ -451,10 +453,21 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
 			gnode->set_show_close_button(true);
 		}
 
+
 		Label *text = memnew( Label );
 		text->set_text(node->get_text());
 		gnode->add_child(text);
 
+		if (node->cast_to<VisualScriptComment>()) {
+			Ref<VisualScriptComment> vsc=node;
+			gnode->set_comment(true);
+			gnode->set_resizeable(true);
+			gnode->set_custom_minimum_size(vsc->get_size()*EDSCALE);
+			gnode->connect("resize_request",this,"_comment_node_resized",varray(E->get()));
+
+		}
+
+
 		int slot_idx=0;
 
 		bool single_seq_output = node->get_output_sequence_port_count()==1 && node->get_output_sequence_port_text(0)==String();
@@ -480,6 +493,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
 			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;
@@ -563,6 +577,10 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
 		}
 
 		graph->add_child(gnode);
+
+		if (gnode->is_comment()) {
+			graph->move_child(gnode,0);
+		}
 	}
 
 	_update_graph_connections();
@@ -2340,6 +2358,39 @@ void VisualScriptEditor::_graph_ofs_changed(const Vector2& p_ofs) {
 	updating_graph=false;
 }
 
+void VisualScriptEditor::_comment_node_resized(const Vector2& p_new_size,int p_node) {
+
+	if (updating_graph)
+		return;
+
+	Ref<VisualScriptComment> vsc = script->get_node(edited_func,p_node);
+	if (vsc.is_null())
+		return;
+
+	Node *node = graph->get_node(itos(p_node));
+	if (!node)
+		return;
+	GraphNode *gn = node->cast_to<GraphNode>();
+	if (!gn)
+		return;
+
+	updating_graph=true;
+
+	graph->set_block_minimum_size_adjust(true); //faster resize
+
+	undo_redo->create_action("Resize Comment",true);
+	undo_redo->add_do_method(vsc.ptr(),"set_size",p_new_size/EDSCALE);
+	undo_redo->add_undo_method(vsc.ptr(),"set_size",vsc->get_size());
+	undo_redo->commit_action();
+
+	gn->set_custom_minimum_size(p_new_size); //for this time since graph update is blocked
+	gn->set_size(Size2(1,1));
+	graph->set_block_minimum_size_adjust(false);
+	updating_graph=false;
+
+
+}
+
 void VisualScriptEditor::_menu_option(int p_what) {
 
 	switch(p_what) {
@@ -2375,7 +2426,150 @@ void VisualScriptEditor::_menu_option(int p_what) {
 			//popup disappearing grabs focus to owner, so use call deferred
 			node_filter->call_deferred("grab_focus");
 			node_filter->call_deferred("select_all");
+		} break;			
+		case EDIT_COPY_NODES:
+		case EDIT_CUT_NODES: {
+
+			if (!script->has_function(edited_func))
+				break;
+
+			clipboard.nodes.clear();
+			clipboard.data_connections.clear();
+			clipboard.sequence_connections.clear();
+
+			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()) {
+
+						int id = String(gn->get_name()).to_int();
+						Ref<VisualScriptNode> node = script->get_node(edited_func,id);
+						if (node->cast_to<VisualScriptFunction>()) {
+							EditorNode::get_singleton()->show_warning("Can't copy the function node.");
+							return;
+						}
+						if (node.is_valid()) {
+							clipboard.nodes[id]=node->duplicate();
+							clipboard.nodes_positions[id]=script->get_node_pos(edited_func,id);
+						}
+
+					}
+				}
+			}
+
+			if (clipboard.nodes.empty())
+				break;
+
+			List<VisualScript::SequenceConnection> sequence_connections;
+
+			script->get_sequence_connection_list(edited_func,&sequence_connections);
+
+			for (List<VisualScript::SequenceConnection>::Element *E=sequence_connections.front();E;E=E->next()) {
+
+				if (clipboard.nodes.has(E->get().from_node) && clipboard.nodes.has(E->get().to_node)) {
+
+					clipboard.sequence_connections.insert(E->get());
+				}
+			}
+
+			List<VisualScript::DataConnection> data_connections;
+
+			script->get_data_connection_list(edited_func,&data_connections);
+
+			for (List<VisualScript::DataConnection>::Element *E=data_connections.front();E;E=E->next()) {
+
+				if (clipboard.nodes.has(E->get().from_node) && clipboard.nodes.has(E->get().to_node)) {
+
+					clipboard.data_connections.insert(E->get());
+				}
+			}
+
+			if (p_what==EDIT_CUT_NODES) {
+				_on_nodes_delete(); // oh yeah, also delete on cut
+			}
+
+
 		} break;
+		case EDIT_PASTE_NODES: {
+			if (!script->has_function(edited_func))
+				break;
+
+			if (clipboard.nodes.empty()) {
+				EditorNode::get_singleton()->show_warning("Clipboard is empty!");
+				break;
+			}
+
+			Map<int,int> remap;
+
+			undo_redo->create_action("Paste VisualScript Nodes");
+			int idc=script->get_available_id()+1;
+
+			Set<int> to_select;
+
+			Set<Vector2> existing_positions;
+
+			{
+				List<int> nodes;
+				script->get_node_list(edited_func,&nodes);
+				for (List<int>::Element *E=nodes.front();E;E=E->next()) {
+					Vector2 pos = script->get_node_pos(edited_func,E->get()).snapped(Vector2(2,2));
+					existing_positions.insert(pos);
+				}
+			}
+
+			for (Map<int,Ref<VisualScriptNode> >::Element *E=clipboard.nodes.front();E;E=E->next()) {
+
+
+				Ref<VisualScriptNode> node = E->get()->duplicate();
+
+				int new_id = idc++;
+				to_select.insert(new_id);
+
+				remap[E->key()]=new_id;
+
+				Vector2 paste_pos = clipboard.nodes_positions[E->key()];
+
+				while(existing_positions.has(paste_pos.snapped(Vector2(2,2)))) {
+					paste_pos+=Vector2(20,20)*EDSCALE;
+				}
+
+
+				undo_redo->add_do_method(script.ptr(),"add_node",edited_func,new_id,node,paste_pos);
+				undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id);
+
+			}
+
+			for (Set<VisualScript::SequenceConnection>::Element *E=clipboard.sequence_connections.front();E;E=E->next()) {
+
+
+				undo_redo->add_do_method(script.ptr(),"sequence_connect",edited_func,remap[E->get().from_node],E->get().from_output,remap[E->get().to_node]);
+				undo_redo->add_undo_method(script.ptr(),"sequence_disconnect",edited_func,remap[E->get().from_node],E->get().from_output,remap[E->get().to_node]);
+
+			}
+
+			for (Set<VisualScript::DataConnection>::Element *E=clipboard.data_connections.front();E;E=E->next()) {
+
+
+				undo_redo->add_do_method(script.ptr(),"data_connect",edited_func,remap[E->get().from_node],E->get().from_port,remap[E->get().to_node],E->get().to_port);
+				undo_redo->add_undo_method(script.ptr(),"data_disconnect",edited_func,remap[E->get().from_node],E->get().from_port,remap[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();
+
+			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));
+
+				}
+			}
+		} break;
+
 
 	}
 }
@@ -2403,6 +2597,7 @@ void VisualScriptEditor::_bind_methods() {
 	ObjectTypeDB::bind_method("_menu_option",&VisualScriptEditor::_menu_option);
 	ObjectTypeDB::bind_method("_graph_ofs_changed",&VisualScriptEditor::_graph_ofs_changed);
 	ObjectTypeDB::bind_method("_center_on_node",&VisualScriptEditor::_center_on_node);
+	ObjectTypeDB::bind_method("_comment_node_resized",&VisualScriptEditor::_comment_node_resized);
 
 
 
@@ -2437,6 +2632,11 @@ VisualScriptEditor::VisualScriptEditor() {
 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/delete_selected"), EDIT_DELETE_NODES);
 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/toggle_breakpoint"), EDIT_TOGGLE_BREAKPOINT);
 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/find_node_type"), EDIT_FIND_NODE_TYPE);
+	edit_menu->get_popup()->add_separator();
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/copy_nodes"), EDIT_COPY_NODES);
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/cut_nodes"), EDIT_CUT_NODES);
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/paste_nodes"), EDIT_PASTE_NODES);
+
 	edit_menu->get_popup()->connect("item_pressed",this,"_menu_option");
 
 	main_hsplit = memnew( HSplitContainer );
@@ -2619,7 +2819,10 @@ static void register_editor_callback() {
 
 	ED_SHORTCUT("visual_script_editor/delete_selected", TTR("Delete Selected"));
 	ED_SHORTCUT("visual_script_editor/toggle_breakpoint", TTR("Toggle Breakpoint"), KEY_F9);
-	ED_SHORTCUT("visual_script_editor/find_node_type", TTR("Find Node Tyoe"), KEY_MASK_CMD+KEY_F);
+	ED_SHORTCUT("visual_script_editor/find_node_type", TTR("Find Node Type"), KEY_MASK_CMD+KEY_F);
+	ED_SHORTCUT("visual_script_editor/copy_nodes", TTR("Copy Nodes"), KEY_MASK_CMD+KEY_C);
+	ED_SHORTCUT("visual_script_editor/cut_nodes", TTR("Cut Nodes"), KEY_MASK_CMD+KEY_X);
+	ED_SHORTCUT("visual_script_editor/paste_nodes", TTR("Paste Nodes"), KEY_MASK_CMD+KEY_V);
 
 }
 

+ 14 - 0
modules/visual_script/visual_script_editor.h

@@ -27,6 +27,9 @@ class VisualScriptEditor : public ScriptEditorBase {
 		EDIT_DELETE_NODES,
 		EDIT_TOGGLE_BREAKPOINT,
 		EDIT_FIND_NODE_TYPE,
+		EDIT_COPY_NODES,
+		EDIT_CUT_NODES,
+		EDIT_PASTE_NODES,
 	};
 
 	MenuButton *edit_menu;
@@ -98,6 +101,15 @@ class VisualScriptEditor : public ScriptEditorBase {
 
 	String _validate_name(const String& p_name) const;
 
+	struct Clipboard {
+
+		Map<int,Ref<VisualScriptNode> > nodes;
+		Map<int,Vector2 > nodes_positions;
+
+		Set<VisualScript::SequenceConnection> sequence_connections;
+		Set<VisualScript::DataConnection> data_connections;
+	} clipboard;
+
 
 	int error_line;
 
@@ -149,6 +161,7 @@ class VisualScriptEditor : public ScriptEditorBase {
 	void _menu_option(int p_what);
 
 	void _graph_ofs_changed(const Vector2& p_ofs);
+	void _comment_node_resized(const Vector2& p_new_size,int p_node);
 
 
 protected:
@@ -179,6 +192,7 @@ public:
 	virtual void set_debugger_active(bool p_active);
 	virtual void set_tooltip_request_func(String p_method,Object* p_obj);
 	virtual Control *get_edit_menu();
+	virtual bool can_lose_focus_on_node_selection() { return false; }
 
 	static void register_editor();
 

+ 193 - 0
modules/visual_script/visual_script_flow_control.cpp

@@ -2,6 +2,7 @@
 #include "os/keyboard.h"
 #include "globals.h"
 
+
 //////////////////////////////////////////
 ////////////////RETURN////////////////////
 //////////////////////////////////////////
@@ -1660,6 +1661,197 @@ VisualScriptInputFilter::VisualScriptInputFilter() {
 }
 
 
+//////////////////////////////////////////
+////////////////EVENT TYPE FILTER///////////
+//////////////////////////////////////////
+
+
+int VisualScriptTypeCast::get_output_sequence_port_count() const {
+
+	return 2;
+}
+
+bool VisualScriptTypeCast::has_input_sequence_port() const{
+
+	return true;
+}
+
+int VisualScriptTypeCast::get_input_value_port_count() const{
+
+
+	return 1;
+}
+int VisualScriptTypeCast::get_output_value_port_count() const{
+
+	return 1;
+}
+
+String VisualScriptTypeCast::get_output_sequence_port_text(int p_port) const {
+
+	return p_port==0 ? "yes" : "no";
+}
+
+PropertyInfo VisualScriptTypeCast::get_input_value_port_info(int p_idx) const{
+
+	return PropertyInfo(Variant::OBJECT,"instance");
+}
+
+PropertyInfo VisualScriptTypeCast::get_output_value_port_info(int p_idx) const{
+
+	return PropertyInfo(Variant::OBJECT,"");
+}
+
+
+String VisualScriptTypeCast::get_caption() const {
+
+	return "TypeCast";
+}
+
+String VisualScriptTypeCast::get_text() const {
+
+	if (script!=String())
+		return "Is "+script.get_file()+"?";
+	else
+		return "Is "+base_type+"?";
+}
+
+void VisualScriptTypeCast::set_base_type(const StringName& p_type) {
+
+	if (base_type==p_type)
+		return;
+
+	base_type=p_type;
+	_change_notify();
+	ports_changed_notify();
+}
+
+StringName VisualScriptTypeCast::get_base_type() const{
+
+	return base_type;
+}
+
+void VisualScriptTypeCast::set_base_script(const String& p_path){
+
+	if (script==p_path)
+		return;
+
+	script=p_path;
+	_change_notify();
+	ports_changed_notify();
+
+}
+String VisualScriptTypeCast::get_base_script() const{
+
+	return script;
+}
+
+
+class VisualScriptNodeInstanceTypeCast : public VisualScriptNodeInstance {
+public:
+
+	VisualScriptInstance* instance;
+	StringName base_type;
+	String script;
+
+	//virtual int get_working_memory_size() const { return 0; }
+	//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
+	//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; }
+
+	virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+		Object *obj = *p_inputs[0];
+
+		*p_outputs[0]=Variant();
+
+		if (!obj) {
+			r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+			r_error_str="Instance is null";
+			return 0;
+		}
+
+		if (script!=String()) {
+
+			Ref<Script> obj_script = obj->get_script();
+			if (!obj_script.is_valid()) {
+				return 1; //well, definitely not the script because object we got has no script.
+			}
+
+			if (!ResourceCache::has(script)) {
+				//if the script is not in use by anyone, we can safely assume whathever we got is not casting to it.
+				return 1;
+			}
+			Ref<Script> cast_script = Ref<Resource>(ResourceCache::get(script));
+			if (!cast_script.is_valid()) {
+				r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
+				r_error_str="Script path is not a script: "+script;
+				return 1;
+			}
+
+			while(obj_script.is_valid()) {
+
+				if (cast_script==obj_script) {
+					*p_outputs[0]=*p_inputs[0]; //copy
+					return 0; // it is the script, yey
+				}
+
+				obj_script=obj_script->get_base_script();
+			}
+
+			return 1; //not found sorry
+		}
+
+		if (ObjectTypeDB::is_type(obj->get_type_name(),base_type)) {
+			*p_outputs[0]=*p_inputs[0]; //copy
+			return 0;
+		} else
+			return 1;
+
+	}
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptTypeCast::instance(VisualScriptInstance* p_instance) {
+
+	VisualScriptNodeInstanceTypeCast * instance = memnew(VisualScriptNodeInstanceTypeCast );
+	instance->instance=p_instance;
+	instance->base_type=base_type;
+	instance->script=script;
+	return instance;
+}
+
+
+
+void VisualScriptTypeCast::_bind_methods() {
+
+	ObjectTypeDB::bind_method(_MD("set_base_type","type"),&VisualScriptTypeCast::set_base_type);
+	ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptTypeCast::get_base_type);
+
+	ObjectTypeDB::bind_method(_MD("set_base_script","path"),&VisualScriptTypeCast::set_base_script);
+	ObjectTypeDB::bind_method(_MD("get_base_script"),&VisualScriptTypeCast::get_base_script);
+
+
+	List<String> script_extensions;
+	for(int i=0;i>ScriptServer::get_language_count();i++) {
+		ScriptServer::get_language(i)->get_recognized_extensions(&script_extensions);
+	}
+
+	String script_ext_hint;
+	for (List<String>::Element *E=script_extensions.front();E;E=E->next()) {
+		if (script_ext_hint!=String())
+			script_ext_hint+=",";
+		script_ext_hint+="*."+E->get();
+	}
+
+	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::STRING,"property/base_script",PROPERTY_HINT_FILE,script_ext_hint),_SCS("set_base_script"),_SCS("get_base_script"));
+
+}
+
+VisualScriptTypeCast::VisualScriptTypeCast() {
+
+	base_type="Object";
+}
 
 
 void register_visual_script_flow_control_nodes() {
@@ -1672,6 +1864,7 @@ void register_visual_script_flow_control_nodes() {
 	VisualScriptLanguage::singleton->add_register_func("flow_control/sequence",create_node_generic<VisualScriptSequence>);
 	VisualScriptLanguage::singleton->add_register_func("flow_control/input_select",create_node_generic<VisualScriptInputSelector>);
 	VisualScriptLanguage::singleton->add_register_func("flow_control/input_filter",create_node_generic<VisualScriptInputFilter>);
+	VisualScriptLanguage::singleton->add_register_func("flow_control/type_cast",create_node_generic<VisualScriptTypeCast>);
 
 
 

+ 47 - 0
modules/visual_script/visual_script_flow_control.h

@@ -273,6 +273,53 @@ public:
 	VisualScriptInputFilter();
 };
 
+
+
+
+
+class VisualScriptTypeCast : public VisualScriptNode {
+
+	OBJ_TYPE(VisualScriptTypeCast,VisualScriptNode)
+
+
+	StringName base_type;
+	String script;
+
+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 String get_category() const { return "flow_control"; }
+
+	void set_base_type(const StringName& p_type);
+	StringName get_base_type() const;
+
+	void set_base_script(const String& p_path);
+	String get_base_script() const;
+
+	virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+
+	VisualScriptTypeCast();
+};
+
 void register_visual_script_flow_control_nodes();
 
 

File diff suppressed because it is too large
+ 567 - 179
modules/visual_script/visual_script_func_nodes.cpp


+ 48 - 2
modules/visual_script/visual_script_func_nodes.h

@@ -14,19 +14,36 @@ public:
 		CALL_MODE_INSTANCE,
 		CALL_MODE_BASIC_TYPE,
 	};
+
+	enum RPCCallMode {
+		RPC_DISABLED,
+		RPC_RELIABLE,
+		RPC_UNRELIABLE,
+		RPC_RELIABLE_TO_ID,
+		RPC_UNRELIABLE_TO_ID
+	};
+
 private:
 
 	CallMode call_mode;
 	StringName base_type;
+	String base_script;
 	Variant::Type basic_type;
 	NodePath base_path;
 	StringName function;
 	int use_default_args;
+	RPCCallMode rpc_call_mode;
+
 
 	Node *_get_base_node() const;
 	StringName _get_base_type() const;
 
-	void _update_defargs();
+	MethodInfo method_cache;
+	void _update_method_cache();
+
+	void _set_argument_cache(const Dictionary& p_args);
+	Dictionary _get_argument_cache() const;
+
 protected:
 	virtual void _validate_property(PropertyInfo& property) const;
 
@@ -58,6 +75,9 @@ public:
 	void set_base_type(const StringName& p_type);
 	StringName get_base_type() const;
 
+	void set_base_script(const String& p_path);
+	String get_base_script() const;
+
 	void set_function(const StringName& p_type);
 	StringName get_function() const;
 
@@ -70,12 +90,16 @@ public:
 	void set_use_default_args(int p_amount);
 	int get_use_default_args() const;
 
+	void set_rpc_call_mode(RPCCallMode p_mode);
+	RPCCallMode get_rpc_call_mode() const;
+
 	virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
 
 	VisualScriptFunctionCall();
 };
 
 VARIANT_ENUM_CAST(VisualScriptFunctionCall::CallMode );
+VARIANT_ENUM_CAST(VisualScriptFunctionCall::RPCCallMode );
 
 
 class VisualScriptPropertySet : public VisualScriptNode {
@@ -92,9 +116,12 @@ public:
 	};
 private:
 
+	PropertyInfo type_cache;
+
 	CallMode call_mode;
 	Variant::Type basic_type;	
 	StringName base_type;
+	String base_script;
 	NodePath base_path;
 	StringName property;
 	bool use_builtin_value;
@@ -106,6 +133,12 @@ private:
 
 	void _update_base_type();
 
+	void _update_cache();
+
+	void _set_type_cache(const Dictionary& p_type);
+	Dictionary _get_type_cache() const;
+
+
 protected:
 	virtual void _validate_property(PropertyInfo& property) const;
 
@@ -134,6 +167,9 @@ public:
 	void set_base_type(const StringName& p_type);
 	StringName get_base_type() const;
 
+	void set_base_script(const String& p_path);
+	String get_base_script() const;
+
 	void set_basic_type(Variant::Type p_type);
 	Variant::Type get_basic_type() const;
 
@@ -171,14 +207,17 @@ public:
 		CALL_MODE_SELF,
 		CALL_MODE_NODE_PATH,
 		CALL_MODE_INSTANCE,
-		CALL_MODE_BASIC_TYPE
+		CALL_MODE_BASIC_TYPE,
 
 	};
 private:
 
+	Variant::Type type_cache;
+
 	CallMode call_mode;
 	Variant::Type basic_type;
 	StringName base_type;
+	String base_script;
 	NodePath base_path;
 	StringName property;
 	InputEvent::Type event_type;
@@ -187,6 +226,10 @@ private:
 	Node *_get_base_node() const;
 	StringName _get_base_type() const;
 
+	void _update_cache();
+
+	void _set_type_cache(Variant::Type p_type);
+	Variant::Type _get_type_cache() const;
 
 protected:
 	virtual void _validate_property(PropertyInfo& property) const;
@@ -216,6 +259,9 @@ public:
 	void set_base_type(const StringName& p_type);
 	StringName get_base_type() const;
 
+	void set_base_script(const String& p_path);
+	String get_base_script() const;
+
 	void set_basic_type(Variant::Type p_type);
 	Variant::Type get_basic_type() const;
 

+ 171 - 0
modules/visual_script/visual_script_nodes.cpp

@@ -62,6 +62,12 @@ bool  VisualScriptFunction::_set(const StringName& p_name, const Variant& p_valu
 		stack_size=p_value;
 		return true;
 	}
+
+	if (p_name=="rpc/mode") {
+		rpc_mode=ScriptInstance::RPCMode(int(p_value));
+		return true;
+	}
+
 	return false;
 }
 
@@ -99,6 +105,11 @@ bool  VisualScriptFunction::_get(const StringName& p_name,Variant &r_ret) const
 		return true;
 	}
 
+	if (p_name=="rpc/mode") {
+		r_ret=rpc_mode;
+		return true;
+	}
+
 	return false;
 }
 void  VisualScriptFunction::_get_property_list( List<PropertyInfo> *p_list) const {
@@ -118,6 +129,7 @@ void  VisualScriptFunction::_get_property_list( List<PropertyInfo> *p_list) cons
 		p_list->push_back(PropertyInfo(Variant::INT,"stack/size",PROPERTY_HINT_RANGE,"1,100000"));
 	}
 	p_list->push_back(PropertyInfo(Variant::BOOL,"stack/stackless"));
+	p_list->push_back(PropertyInfo(Variant::INT,"rpc/mode",PROPERTY_HINT_ENUM,"Disabled,Remote,Sync,Master,Slave"));
 
 }
 
@@ -224,6 +236,16 @@ int VisualScriptFunction::get_argument_count() const {
 	return arguments.size();
 }
 
+
+void VisualScriptFunction::set_rpc_mode(ScriptInstance::RPCMode p_mode) {
+	rpc_mode=p_mode;
+}
+
+ScriptInstance::RPCMode VisualScriptFunction::get_rpc_mode() const {
+	return rpc_mode;
+}
+
+
 class VisualScriptNodeInstanceFunction : public VisualScriptNodeInstance {
 public:
 
@@ -272,6 +294,7 @@ VisualScriptFunction::VisualScriptFunction() {
 
 	stack_size=256;
 	stack_less=false;
+	rpc_mode=ScriptInstance::RPC_MODE_DISABLED;
 }
 
 
@@ -2432,6 +2455,153 @@ VisualScriptSubCall::VisualScriptSubCall() {
 
 }
 
+//////////////////////////////////////////
+////////////////Comment///////////
+//////////////////////////////////////////
+
+int VisualScriptComment::get_output_sequence_port_count() const {
+
+	return 0;
+}
+
+bool VisualScriptComment::has_input_sequence_port() const{
+
+	return false;
+}
+
+int VisualScriptComment::get_input_value_port_count() const{
+	return 0;
+}
+int VisualScriptComment::get_output_value_port_count() const{
+
+	return 0;
+}
+
+String VisualScriptComment::get_output_sequence_port_text(int p_port) const {
+
+	return String();
+}
+
+PropertyInfo VisualScriptComment::get_input_value_port_info(int p_idx) const{
+
+	return PropertyInfo();
+}
+
+PropertyInfo VisualScriptComment::get_output_value_port_info(int p_idx) const{
+
+	return PropertyInfo();
+}
+
+
+String VisualScriptComment::get_caption() const {
+
+	return title;
+}
+
+
+String VisualScriptComment::get_text() const {
+
+	return description;
+}
+
+void VisualScriptComment::set_title(const String& p_title) {
+
+
+	if (title==p_title)
+		return;
+	title=p_title;
+	ports_changed_notify();
+}
+
+String VisualScriptComment::get_title() const{
+
+	return title;
+}
+
+void VisualScriptComment::set_description(const String& p_description){
+
+	if (description==p_description)
+		return;
+	description=p_description;
+	ports_changed_notify();
+
+}
+String VisualScriptComment::get_description() const{
+
+	return description;
+}
+
+void VisualScriptComment::set_size(const Size2& p_size){
+
+	if (size==p_size)
+		return;
+	size=p_size;
+	ports_changed_notify();
+
+}
+Size2 VisualScriptComment::get_size() const{
+
+	return size;
+}
+
+
+String VisualScriptComment::get_category() const {
+
+	return "data";
+}
+
+class VisualScriptNodeInstanceComment : public VisualScriptNodeInstance {
+public:
+
+	VisualScriptInstance* instance;
+
+	//virtual int get_working_memory_size() const { return 0; }
+	//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
+	//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; };
+
+	virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+
+
+		return 0;
+	}
+
+
+};
+
+VisualScriptNodeInstance* VisualScriptComment::instance(VisualScriptInstance* p_instance) {
+
+	VisualScriptNodeInstanceComment * instance = memnew(VisualScriptNodeInstanceComment );
+	instance->instance=p_instance;
+	return instance;
+}
+
+
+
+void VisualScriptComment::_bind_methods() {
+
+
+	ObjectTypeDB::bind_method(_MD("set_title","title"),&VisualScriptComment::set_title);
+	ObjectTypeDB::bind_method(_MD("get_title"),&VisualScriptComment::get_title);
+
+	ObjectTypeDB::bind_method(_MD("set_description","description"),&VisualScriptComment::set_description);
+	ObjectTypeDB::bind_method(_MD("get_description"),&VisualScriptComment::get_description);
+
+	ObjectTypeDB::bind_method(_MD("set_size","size"),&VisualScriptComment::set_size);
+	ObjectTypeDB::bind_method(_MD("get_size"),&VisualScriptComment::get_size);
+
+	ADD_PROPERTY( PropertyInfo(Variant::STRING,"title"),_SCS("set_title"),_SCS("get_title"));
+	ADD_PROPERTY( PropertyInfo(Variant::STRING,"description",PROPERTY_HINT_MULTILINE_TEXT),_SCS("set_description"),_SCS("get_description"));
+	ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"size"),_SCS("set_size"),_SCS("get_size"));
+
+}
+
+VisualScriptComment::VisualScriptComment() {
+
+	title="Comment";
+	size=Size2(150,150);
+}
+
+
 
 void register_visual_script_nodes() {
 
@@ -2447,6 +2617,7 @@ void register_visual_script_nodes() {
 	VisualScriptLanguage::singleton->add_register_func("data/self",create_node_generic<VisualScriptSelf>);
 	VisualScriptLanguage::singleton->add_register_func("custom/custom_node",create_node_generic<VisualScriptCustomNode>);
 	VisualScriptLanguage::singleton->add_register_func("custom/sub_call",create_node_generic<VisualScriptSubCall>);
+	VisualScriptLanguage::singleton->add_register_func("data/comment",create_node_generic<VisualScriptComment>);
 
 
 	VisualScriptLanguage::singleton->add_register_func("index/get_index",create_node_generic<VisualScriptIndexGet>);

+ 49 - 0
modules/visual_script/visual_script_nodes.h

@@ -17,6 +17,7 @@ class VisualScriptFunction : public VisualScriptNode {
 
 	bool stack_less;
 	int stack_size;
+	ScriptInstance::RPCMode rpc_mode;
 
 
 protected:
@@ -60,6 +61,9 @@ public:
 	void set_stack_size(int p_size);
 	int get_stack_size() const;
 
+	void set_rpc_mode(ScriptInstance::RPCMode p_mode);
+	ScriptInstance::RPCMode get_rpc_mode() const;
+
 	virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
 
 	VisualScriptFunction();
@@ -645,6 +649,51 @@ public:
 	VisualScriptSubCall();
 };
 
+class VisualScriptComment: public VisualScriptNode {
+
+	OBJ_TYPE(VisualScriptComment,VisualScriptNode)
+
+
+	String title;
+	String description;
+	Size2 size;
+protected:
+
+	virtual bool _use_builtin_script() const { return true; }
+
+	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 String get_category() const;
+
+	void set_title(const String& p_title);
+	String get_title() const;
+
+	void set_description(const String& p_description);
+	String get_description() const;
+
+	void set_size(const Size2& p_size);
+	Size2 get_size() const;
+
+	virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance);
+
+	VisualScriptComment();
+};
 
 void register_visual_script_nodes();
 

+ 9 - 6
modules/visual_script/visual_script_yield_nodes.cpp

@@ -45,12 +45,13 @@ PropertyInfo VisualScriptYield::get_output_value_port_info(int p_idx) const{
 
 String VisualScriptYield::get_caption() const {
 
-	return "Wait";
+	return yield_mode==YIELD_RETURN?"Yield":"Wait";
 }
 
 String VisualScriptYield::get_text() const {
 
 	switch (yield_mode) {
+		case YIELD_RETURN: return ""; break;
 		case YIELD_FRAME: return "Next Frame"; break;
 		case YIELD_FIXED_FRAME:  return "Next Fixed Frame"; break;
 		case YIELD_WAIT:  return rtos(wait_time)+" sec(s)"; break;
@@ -88,8 +89,10 @@ public:
 			Ref<VisualScriptFunctionState> state;
 			state.instance();
 
+			int ret = STEP_YIELD_BIT;
 			switch(mode) {
 
+				case VisualScriptYield::YIELD_RETURN:  ret=STEP_EXIT_FUNCTION_BIT; break; //return the yield
 				case VisualScriptYield::YIELD_FRAME: state->connect_to_signal(tree,"idle_frame",Array()); break;
 				case VisualScriptYield::YIELD_FIXED_FRAME:  state->connect_to_signal(tree,"fixed_frame",Array()); break;
 				case VisualScriptYield::YIELD_WAIT:  state->connect_to_signal(tree->create_timer(wait_time).ptr(),"timeout",Array()); break;
@@ -98,7 +101,7 @@ public:
 
 			*p_working_mem=state;
 
-			return STEP_YIELD_BIT;
+			return ret;
 		}
 	}
 
@@ -487,7 +490,7 @@ void VisualScriptYieldSignal::_bind_methods() {
 		bt+=Variant::get_type_name(Variant::Type(i));
 	}
 
-	ADD_PROPERTY(PropertyInfo(Variant::INT,"signal/call_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance",PROPERTY_USAGE_NOEDITOR),_SCS("set_call_mode"),_SCS("get_call_mode"));
+	ADD_PROPERTY(PropertyInfo(Variant::INT,"signal/call_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance"),_SCS("set_call_mode"),_SCS("get_call_mode"));
 	ADD_PROPERTY(PropertyInfo(Variant::STRING,"signal/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type"));
 	ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"signal/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_base_path"),_SCS("get_base_path"));
 	ADD_PROPERTY(PropertyInfo(Variant::STRING,"signal/signal"),_SCS("set_signal"),_SCS("get_signal"));
@@ -615,8 +618,8 @@ void register_visual_script_yield_nodes() {
 	VisualScriptLanguage::singleton->add_register_func("functions/wait/wait_fixed_frame",create_yield_node<VisualScriptYield::YIELD_FIXED_FRAME>);
 	VisualScriptLanguage::singleton->add_register_func("functions/wait/wait_time",create_yield_node<VisualScriptYield::YIELD_WAIT>);
 
-	VisualScriptLanguage::singleton->add_register_func("functions/yield/instance_signal",create_yield_signal_node<VisualScriptYieldSignal::CALL_MODE_INSTANCE>);
-	VisualScriptLanguage::singleton->add_register_func("functions/yield/self_signal",create_yield_signal_node<VisualScriptYieldSignal::CALL_MODE_SELF>);
-	VisualScriptLanguage::singleton->add_register_func("functions/yield/node_signal",create_yield_signal_node<VisualScriptYieldSignal::CALL_MODE_NODE_PATH>);
+
+	VisualScriptLanguage::singleton->add_register_func("functions/yield",create_yield_node<VisualScriptYield::YIELD_RETURN>);
+	VisualScriptLanguage::singleton->add_register_func("functions/yield_signal",create_node_generic<VisualScriptYieldSignal>);
 
 }

+ 1 - 0
modules/visual_script/visual_script_yield_nodes.h

@@ -9,6 +9,7 @@ class VisualScriptYield : public VisualScriptNode {
 public:
 
 	enum YieldMode {
+		YIELD_RETURN,
 		YIELD_FRAME,
 		YIELD_FIXED_FRAME,
 		YIELD_WAIT

+ 8 - 1
scene/gui/control.cpp

@@ -2214,7 +2214,7 @@ void Control::grab_click_focus() {
 
 void Control::minimum_size_changed() {
 
-	if (!is_inside_tree())
+	if (!is_inside_tree() || data.block_minimum_size_adjust)
 		return;
 
 	if (data.pending_min_size_update)
@@ -2374,8 +2374,14 @@ Control *Control::get_root_parent_control() const {
 	return const_cast<Control*>(root);
 }
 
+void Control::set_block_minimum_size_adjust(bool p_block) {
+	data.block_minimum_size_adjust=p_block;
+}
 
+bool Control::is_minimum_size_adjust_blocked() const {
 
+	return data.block_minimum_size_adjust;
+}
 void Control::_bind_methods() {
 
 
@@ -2603,6 +2609,7 @@ Control::Control() {
 	data.scale=Vector2(1,1);
 	data.drag_owner=0;
 	data.modal_frame=0;
+	data.block_minimum_size_adjust=false;
 
 
 	for (int i=0;i<4;i++) {

+ 6 - 0
scene/gui/control.h

@@ -128,6 +128,8 @@ private:
 		bool ignore_mouse;
 		bool stop_mouse;
 
+		bool block_minimum_size_adjust;
+
 		Control *parent;
 		ObjectID drag_owner;
 		bool modal;
@@ -396,6 +398,10 @@ public:
 
 	Control *get_root_parent_control() const;
 
+
+	void set_block_minimum_size_adjust(bool p_block);
+	bool is_minimum_size_adjust_blocked() const;
+
 	Control();
 	~Control();
 

+ 12 - 0
scene/gui/graph_edit.cpp

@@ -193,6 +193,9 @@ void GraphEdit::_graph_node_raised(Node* p_gn) {
 	GraphNode *gn=p_gn->cast_to<GraphNode>();
 	ERR_FAIL_COND(!gn);
 	gn->raise();
+	if (gn->is_comment()) {
+		move_child(gn,0);
+	}
 	top_layer->raise();
 	emit_signal("node_selected",p_gn);
 
@@ -261,6 +264,7 @@ void GraphEdit::_notification(int p_what) {
 
 	}
 	if (p_what==NOTIFICATION_DRAW) {
+
 		draw_style_box( get_stylebox("bg"),Rect2(Point2(),get_size()) );
 		VS::get_singleton()->canvas_item_set_clip(get_canvas_item(),true);
 
@@ -712,6 +716,10 @@ void GraphEdit::_top_layer_draw() {
 			col.g+=0.4;
 			col.b+=0.4;
 		}
+
+		if (!connecting_out) {
+			SWAP(pos,topos);
+		}
 		_draw_cos_line(top_layer,pos,topos,col,col);
 	}
 
@@ -856,6 +864,10 @@ void GraphEdit::_input_event(const InputEvent& p_ev) {
 				gn=get_child(i)->cast_to<GraphNode>();
 
 				if (gn) {
+
+					if (gn->is_resizing())
+						continue;
+
 					Rect2 r = gn->get_rect();
 					r.size*=zoom;
 					if (r.has_point(get_local_mouse_pos()))

+ 2 - 0
scene/gui/graph_edit.h

@@ -133,6 +133,7 @@ private:
 	bool lines_on_bg;
 
 
+
 	struct ConnType {
 
 		union {
@@ -205,6 +206,7 @@ public:
 	int get_snap() const;
 	void set_snap(int p_snap);
 
+
 	GraphEdit();
 };
 

+ 74 - 3
scene/gui/graph_node.cpp

@@ -188,11 +188,13 @@ void GraphNode::_notification(int p_what) {
 
 	if (p_what==NOTIFICATION_DRAW) {
 
-		Ref<StyleBox> sb=get_stylebox(selected ? "selectedframe" : "frame");
+		Ref<StyleBox> sb=get_stylebox(comment? "comment": (selected ? "selectedframe" : "frame"));
+
 		sb=sb->duplicate();
 		sb->call("set_modulate",modulate);
 		Ref<Texture> port =get_icon("port");
 		Ref<Texture> close =get_icon("close");
+		Ref<Texture> resizer =get_icon("resizer");
 		int close_offset = get_constant("close_offset");
 		Ref<Font> title_font = get_font("title_font");
 		int title_offset = get_constant("title_offset");
@@ -258,6 +260,11 @@ void GraphNode::_notification(int p_what) {
 			}
 
 		}
+
+
+		if (resizeable) {
+			draw_texture(resizer,get_size()-resizer->get_size());
+		}
 	}
 
 	if (p_what==NOTIFICATION_SORT_CHILDREN) {
@@ -594,19 +601,49 @@ void GraphNode::_input_event(const InputEvent& p_ev) {
 		ERR_EXPLAIN("GraphNode must be the child of a GraphEdit node.");
 		ERR_FAIL_COND(get_parent_control() == NULL);
 
-		get_parent_control()->grab_focus();
-
 		if(p_ev.mouse_button.pressed && p_ev.mouse_button.button_index==BUTTON_LEFT) {
 
 			Vector2 mpos = Vector2(p_ev.mouse_button.x,p_ev.mouse_button.y);
 			if (close_rect.size!=Size2() && close_rect.has_point(mpos)) {
 				emit_signal("close_request");
+				accept_event();
+				return;
+			}
+
+			Ref<Texture> resizer =get_icon("resizer");
+
+			if (resizeable && mpos.x > get_size().x-resizer->get_width() && mpos.y > get_size().y-resizer->get_height()) {
+
+				resizing=true;
+				resizing_from=mpos;
+				resizing_from_size=get_size();
+				accept_event();
 				return;
 			}
+
+			//send focus to parent
 			emit_signal("raise_request");
+			get_parent_control()->grab_focus();
+
 		}
+
+		if(!p_ev.mouse_button.pressed && p_ev.mouse_button.button_index==BUTTON_LEFT) {
+			resizing=false;
+		}
+
+	}
+
+
+	if (resizing && p_ev.type==InputEvent::MOUSE_MOTION) {
+		Vector2 mpos = Vector2(p_ev.mouse_motion.x,p_ev.mouse_motion.y);
+
+		Vector2 diff = mpos - resizing_from;
+
+		emit_signal("resize_request",resizing_from_size+diff);
+
 	}
 
+
 }
 
 void GraphNode::set_modulate(const Color &p_color) {
@@ -630,6 +667,30 @@ GraphNode::Overlay GraphNode::get_overlay() const{
 	return overlay;
 }
 
+void GraphNode::set_comment(bool p_enable) {
+
+	comment=p_enable;
+	update();
+}
+
+bool GraphNode::is_comment() const{
+
+	return comment;
+}
+
+
+void GraphNode::set_resizeable(bool p_enable) {
+
+	resizeable=p_enable;
+	update();
+}
+
+bool GraphNode::is_resizeable() const{
+
+	return resizeable;
+}
+
+
 void GraphNode::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("set_title","title"),&GraphNode::set_title);
@@ -649,6 +710,12 @@ void GraphNode::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("set_offset","offset"),&GraphNode::set_offset);
 	ObjectTypeDB::bind_method(_MD("get_offset"),&GraphNode::get_offset);
 
+	ObjectTypeDB::bind_method(_MD("set_comment","comment"),&GraphNode::set_comment);
+	ObjectTypeDB::bind_method(_MD("is_comment"),&GraphNode::is_comment);
+
+	ObjectTypeDB::bind_method(_MD("set_resizeable","resizeable"),&GraphNode::set_resizeable);
+	ObjectTypeDB::bind_method(_MD("is_resizeable"),&GraphNode::is_resizeable);
+
 	ObjectTypeDB::bind_method(_MD("get_connection_output_count"),&GraphNode::get_connection_output_count);
 	ObjectTypeDB::bind_method(_MD("get_connection_input_count"),&GraphNode::get_connection_input_count);
 
@@ -675,6 +742,7 @@ void GraphNode::_bind_methods() {
 	ADD_SIGNAL(MethodInfo("dragged",PropertyInfo(Variant::VECTOR2,"from"),PropertyInfo(Variant::VECTOR2,"to")));
 	ADD_SIGNAL(MethodInfo("raise_request"));
 	ADD_SIGNAL(MethodInfo("close_request"));
+	ADD_SIGNAL(MethodInfo("resize_request",PropertyInfo(Variant::VECTOR2,"new_minsize")));
 
 	BIND_CONSTANT( OVERLAY_DISABLED );
 	BIND_CONSTANT( OVERLAY_BREAKPOINT );
@@ -688,4 +756,7 @@ GraphNode::GraphNode() {
 	connpos_dirty=true;
 	set_stop_mouse(false);
 	modulate=Color(1,1,1,1);
+	comment=false;
+	resizeable=false;
+	resizing=false;
 }

+ 14 - 0
scene/gui/graph_node.h

@@ -60,6 +60,12 @@ private:
 	String title;
 	bool show_close;
 	Vector2 offset;
+	bool comment;
+	bool resizeable;
+
+	bool resizing;
+	Vector2 resizing_from;
+	Vector2 resizing_from_size;
 
 	Rect2 close_rect;
 
@@ -144,8 +150,16 @@ public:
 	void set_overlay(Overlay p_overlay);
 	Overlay get_overlay() const;
 
+	void set_comment(bool p_enable);
+	bool is_comment() const;
+
+	void set_resizeable(bool p_enable);
+	bool is_resizeable() const;
+
 	virtual Size2 get_minimum_size() const;
 
+	bool is_resizing() const { return resizing; }
+
 	GraphNode();
 };
 

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

@@ -627,6 +627,7 @@ void fill_default_theme(Ref<Theme>& t,const Ref<Font> & default_font,const Ref<F
 	// GraphNode
 
 	Ref<StyleBoxTexture> graphsb = make_stylebox(graph_node_png,6,24,6,5,16,24,16,5);
+	Ref<StyleBoxTexture> graphsbcomment = make_stylebox(graph_node_comment_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> graphsbdeffocus = make_stylebox(graph_node_default_focus_png,4,4,4,4,6,4,4,4);
@@ -639,11 +640,13 @@ void fill_default_theme(Ref<Theme>& t,const Ref<Font> & default_font,const Ref<F
 	t->set_stylebox("selectedframe","GraphNode", graphsbselected );
 	t->set_stylebox("defaultframe", "GraphNode", graphsbdefault );
 	t->set_stylebox("defaultfocus", "GraphNode", graphsbdeffocus );
+	t->set_stylebox("comment", "GraphNode", graphsbcomment );
 	t->set_stylebox("breakpoint", "GraphNode", graph_bpoint );
 	t->set_stylebox("position", "GraphNode", graph_position );
 	t->set_constant("separation","GraphNode", 1 *scale);
 	t->set_icon("port","GraphNode", make_icon( graph_port_png ) );
 	t->set_icon("close","GraphNode", make_icon( graph_node_close_png ) );
+	t->set_icon("resizer","GraphNode", make_icon( window_resizer_png ) );
 	t->set_font("title_font","GraphNode", default_font );
 	t->set_color("title_color","GraphNode", Color(0,0,0,1));
 	t->set_constant("title_offset","GraphNode", 20 *scale);

BIN
scene/resources/default_theme/graph_node_comment.png


File diff suppressed because it is too large
+ 1 - 0
scene/resources/default_theme/theme_data.h


BIN
scene/resources/default_theme/window_resizer.png


+ 1 - 1
tools/editor/editor_node.cpp

@@ -1673,7 +1673,7 @@ void EditorNode::_edit_current() {
 
 	if (main_plugin) {
 
-		if (main_plugin!=editor_plugin_screen) {
+		if (main_plugin!=editor_plugin_screen && (!ScriptEditor::get_singleton() || !ScriptEditor::get_singleton()->is_visible() || ScriptEditor::get_singleton()->can_take_away_focus())) {
 
 			// update screen main_plugin
 

+ 27 - 2
tools/editor/plugins/script_editor_plugin.cpp

@@ -987,6 +987,20 @@ void ScriptEditor::_notification(int p_what) {
 
 }
 
+bool ScriptEditor::can_take_away_focus() const {
+
+	int selected = tab_container->get_current_tab();
+	if (selected<0 || selected>=tab_container->get_child_count())
+		return true;
+
+	ScriptEditorBase *current = tab_container->get_child(selected)->cast_to<ScriptEditorBase>();
+	if (!current)
+		return true;
+
+
+	return current->can_lose_focus_on_node_selection();
+
+}
 
 void ScriptEditor::close_builtin_scripts_from_scene(const String& p_scene) {
 
@@ -1397,7 +1411,7 @@ void ScriptEditor::_update_script_names() {
 
 
 
-void ScriptEditor::edit(const Ref<Script>& p_script) {
+void ScriptEditor::edit(const Ref<Script>& p_script, bool p_grab_focus) {
 
 	if (p_script.is_null())
 		return;
@@ -1471,7 +1485,9 @@ void ScriptEditor::edit(const Ref<Script>& p_script) {
 	}
 
 
-	_go_to_tab(tab_container->get_tab_count()-1);
+	if (p_grab_focus) {
+		_go_to_tab(tab_container->get_tab_count()-1);
+	}
 
 
 
@@ -1932,6 +1948,13 @@ void ScriptEditor::_help_search(String p_text) {
 	help_search_dialog->popup(p_text);
 }
 
+void ScriptEditor::_open_script_request(const String& p_path) {
+
+	Ref<Script> script = ResourceLoader::load(p_path);
+	if (script.is_valid()) {
+		script_editor->edit(script,false);
+	}
+}
 
 int ScriptEditor::script_editor_func_count=0;
 CreateScriptEditorFunc ScriptEditor::script_editor_funcs[ScriptEditor::SCRIPT_EDITOR_FUNC_MAX];
@@ -2208,6 +2231,8 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
 
 	edit_pass=0;
 	trim_trailing_whitespace_on_save = false;
+
+	ScriptServer::edit_request_func=_open_script_request;
 }
 
 

+ 6 - 1
tools/editor/plugins/script_editor_plugin.h

@@ -101,6 +101,7 @@ public:
 	virtual void add_callback(const String& p_function,StringArray p_args)=0;
 	virtual void update_settings()=0;
 	virtual void set_debugger_active(bool p_active)=0;
+	virtual bool can_lose_focus_on_node_selection() { return true; }
 
 	virtual void set_tooltip_request_func(String p_method,Object* p_obj)=0;
 	virtual Control *get_edit_menu()=0;
@@ -285,6 +286,8 @@ class ScriptEditor : public VBoxContainer {
 	int file_dialog_option;
 	void _file_dialog_action(String p_file);
 
+	static void _open_script_request(const String& p_path);
+
 	static ScriptEditor *script_editor;
 protected:
 	void _notification(int p_what);
@@ -297,7 +300,7 @@ public:
 	void apply_scripts() const;
 
 	void ensure_select_current();
-	void edit(const Ref<Script>& p_script);
+	void edit(const Ref<Script>& p_script,bool p_grab_focus=true);
 
 	Dictionary get_state() const;
 	void set_state(const Dictionary& p_state);
@@ -322,6 +325,8 @@ public:
 
 	void goto_help(const String& p_desc) { _help_class_goto(p_desc); }
 
+	bool can_take_away_focus() const;
+
 	ScriptEditorDebugger *get_debugger() { return debugger; }
 	void set_live_auto_reload_running_scripts(bool p_enabled);
 

+ 1 - 0
tools/editor/property_editor.cpp

@@ -1151,6 +1151,7 @@ void CustomPropertyEditor::_action_pressed(int p_which) {
 
 					file->clear_filters();
 
+
 					if (hint_text!="") {
 						Vector<String> extensions=hint_text.split(",");
 						for(int i=0;i<extensions.size();i++) {

+ 1 - 0
tools/editor/property_selector.cpp

@@ -508,6 +508,7 @@ void PropertySelector::select_property_from_base_type(const String& p_base,const
 void PropertySelector::select_property_from_script(const Ref<Script>& p_script,const String& p_current){
 
 	ERR_FAIL_COND( p_script.is_null() );
+
 	base_type=p_script->get_instance_base_type();
 	selected=p_current;
 	type=Variant::NIL;

Some files were not shown because too many files changed in this diff