瀏覽代碼

Likely with bugs and with some features are missing, as well as profiler support, but VisualScript should be more or less done!

Juan Linietsky 9 年之前
父節點
當前提交
9890c1d2ca

+ 1 - 1
core/variant.cpp

@@ -1510,7 +1510,7 @@ Variant::operator String() const {
 
 	switch( type ) {
 
-		case NIL: return "";
+		case NIL: return "Null";
 		case BOOL: return _data._bool ? "True" : "False";
 		case INT: return String::num(_data._int);
 		case REAL: return String::num(_data._real);

+ 1 - 1
modules/gdscript/gd_editor.cpp

@@ -335,7 +335,7 @@ String GDScriptLanguage::make_function(const String& p_class,const String& p_nam
 		for(int i=0;i<p_args.size();i++) {
 			if (i>0)
 				s+=", ";
-			s+=p_args[i];
+			s+=p_args[i].get_slice(":",0);
 		}
 		s+=" ";
 	}

+ 283 - 17
modules/visual_script/visual_script.cpp

@@ -1,8 +1,19 @@
 #include "visual_script.h"
 #include "visual_script_nodes.h"
-
+#include "globals.h"
 #define SCRIPT_VARIABLES_PREFIX "script_variables/"
 
+
+//used by editor, this is not really saved
+void VisualScriptNode::set_breakpoint(bool p_breakpoint) {
+	breakpoint=p_breakpoint;
+}
+
+bool VisualScriptNode::is_breakpoint() const {
+
+	return breakpoint;
+}
+
 void VisualScriptNode::_notification(int p_what) {
 
 	if (p_what==NOTIFICATION_POSTINITIALIZE) {
@@ -96,6 +107,10 @@ Ref<VisualScript> VisualScriptNode::get_visual_script() const {
 
 }
 
+VisualScriptNode::VisualScriptNode() {
+	breakpoint=false;
+}
+
 ////////////////
 
 /////////////////////
@@ -129,6 +144,7 @@ void VisualScript::add_function(const StringName& p_name) {
 	ERR_FAIL_COND(functions.has(p_name));
 
 	functions[p_name]=Function();
+	functions[p_name].scroll=Vector2(-50,-100);
 }
 
 bool VisualScript::has_function(const StringName& p_name) const {
@@ -169,6 +185,21 @@ void VisualScript::rename_function(const StringName& p_name,const StringName& p_
 
 }
 
+void VisualScript::set_function_scroll(const StringName& p_name, const Vector2& p_scroll) {
+
+	ERR_FAIL_COND(!functions.has(p_name));
+	functions[p_name].scroll=p_scroll;
+
+}
+
+Vector2 VisualScript::get_function_scroll(const StringName& p_name) const {
+
+	ERR_FAIL_COND_V(!functions.has(p_name),Vector2());
+	return functions[p_name].scroll;
+
+}
+
+
 void VisualScript::get_function_list(List<StringName> *r_functions) const {
 
 	for (const Map<StringName,Function>::Element *E=functions.front();E;E=E->next()) {
@@ -338,6 +369,13 @@ void VisualScript::remove_node(const StringName& p_func,int p_id){
 }
 
 
+bool VisualScript::has_node(const StringName& p_func,int p_id) const {
+
+	ERR_FAIL_COND_V(!functions.has(p_func),false);
+	const Function &func = functions[p_func];
+
+	return func.nodes.has(p_id);
+}
 
 Ref<VisualScriptNode> VisualScript::get_node(const StringName& p_func,int p_id) const{
 
@@ -1012,10 +1050,13 @@ void VisualScript::_set_data(const Dictionary& p_data) {
 
 		Dictionary func=funcs[i];
 
+
 		StringName name=func["name"];
 		//int id=func["function_id"];
 		add_function(name);
 
+		set_function_scroll(name,func["scroll"]);
+
 		Array nodes = func["nodes"];
 
 		for(int i=0;i<nodes.size();i+=3) {
@@ -1083,6 +1124,7 @@ Dictionary VisualScript::_get_data() const{
 		Dictionary func;
 		func["name"]=E->key();
 		func["function_id"]=E->get().function_id;
+		func["scroll"]=E->get().scroll;
 
 		Array nodes;
 
@@ -1144,12 +1186,15 @@ void VisualScript::_bind_methods() {
 	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("set_function_scroll","ofs"),&VisualScript::set_function_scroll);
+	ObjectTypeDB::bind_method(_MD("get_function_scroll"),&VisualScript::get_function_scroll);
 
 	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("has_node","func","id"),&VisualScript::has_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);
 
@@ -1306,8 +1351,8 @@ bool VisualScriptInstance::has_method(const StringName& p_method) const{
 }
 
 
-//#define VSDEBUG(m_text) print_line(m_text)
-#define VSDEBUG(m_text)
+#define VSDEBUG(m_text) print_line(m_text)
+//#define VSDEBUG(m_text)
 
 Variant VisualScriptInstance::call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error){
 
@@ -1395,9 +1440,14 @@ Variant VisualScriptInstance::call(const StringName& p_method,const Variant** p_
 	String error_str;
 
 	bool error=false;
-	int current_node_id;
+	int current_node_id=f->node;
 	Variant return_value;
-
+	Variant *working_mem=NULL;
+#ifdef DEBUG_ENABLED
+	if (ScriptDebugger::get_singleton()) {
+		VisualScriptLanguage::singleton->enter_function(this,&p_method,variant_stack,&working_mem,&current_node_id);
+	}
+#endif
 
 	while(true) {
 
@@ -1408,7 +1458,7 @@ Variant VisualScriptInstance::call(const StringName& p_method,const Variant** p_
 
 
 		//setup working mem
-		Variant *working_mem=node->working_mem_idx>=0 ? &variant_stack[node->working_mem_idx] : (Variant*)NULL;
+		working_mem=node->working_mem_idx>=0 ? &variant_stack[node->working_mem_idx] : (Variant*)NULL;
 
 		VSDEBUG("WORKING MEM: "+itos(node->working_mem_idx));
 
@@ -1440,6 +1490,7 @@ Variant VisualScriptInstance::call(const StringName& p_method,const Variant** p_
 						r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
 						current_node_id=ug->from->get_id();
 						error=true;
+						working_mem=NULL;
 						break;
 					}
 
@@ -1469,6 +1520,7 @@ Variant VisualScriptInstance::call(const StringName& p_method,const Variant** p_
 
 		bool start_sequence = flow_stack && !(flow_stack[flow_stack_pos] & VisualScriptNodeInstance::FLOW_STACK_PUSHED_BIT); //if there is a push bit, it means we are continuing a sequence
 
+
 		VSDEBUG("STEP - STARTSEQ: "+itos(start_sequence));
 
 		int ret = node->step(input_args,output_args,start_sequence,working_mem,r_error,error_str);
@@ -1479,6 +1531,30 @@ Variant VisualScriptInstance::call(const StringName& p_method,const Variant** p_
 			break;
 		}
 
+#ifdef DEBUG_ENABLED
+		if (ScriptDebugger::get_singleton()) {
+			// line
+			bool do_break=false;
+
+			if (ScriptDebugger::get_singleton()->get_lines_left()>0) {
+
+				if (ScriptDebugger::get_singleton()->get_depth()<=0)
+					ScriptDebugger::get_singleton()->set_lines_left( ScriptDebugger::get_singleton()->get_lines_left() -1 );
+				if (ScriptDebugger::get_singleton()->get_lines_left()<=0)
+					do_break=true;
+			}
+
+			if (ScriptDebugger::get_singleton()->is_breakpoint(current_node_id,source))
+				do_break=true;
+
+			if (do_break) {
+				VisualScriptLanguage::singleton->debug_break("Breakpoint",true);
+			}
+
+			ScriptDebugger::get_singleton()->line_poll();
+
+		}
+#endif
 		int output = ret & VisualScriptNodeInstance::STEP_MASK;
 
 		VSDEBUG("STEP RETURN: "+itos(ret));
@@ -1573,6 +1649,7 @@ Variant VisualScriptInstance::call(const StringName& p_method,const Variant** p_
 						break;
 					}
 
+					node=next;
 					VSDEBUG("RE-ENTERED A LOOP, RETURNED STACK POS TO - "+itos(flow_stack_pos));
 
 				} else {
@@ -1638,8 +1715,10 @@ Variant VisualScriptInstance::call(const StringName& p_method,const Variant** p_
 		//if (!GDScriptLanguage::get_singleton()->debug_break(err_text,false)) {
 			// debugger break did not happen
 
-		VSDEBUG("ERRSTR: "+error_str);
-		_err_print_error(err_func.utf8().get_data(),err_file.utf8().get_data(),err_line,error_str.utf8().get_data(),ERR_HANDLER_SCRIPT);
+		if (!VisualScriptLanguage::singleton->debug_break(error_str,false)) {
+
+			_err_print_error(err_func.utf8().get_data(),err_file.utf8().get_data(),err_line,error_str.utf8().get_data(),ERR_HANDLER_SCRIPT);
+		}
 
 		//}
 	} else {
@@ -1648,6 +1727,11 @@ Variant VisualScriptInstance::call(const StringName& p_method,const Variant** p_
 		//return_value=
 	}
 
+#ifdef DEBUG_ENABLED
+	if (ScriptDebugger::get_singleton()) {
+		VisualScriptLanguage::singleton->exit_function();
+	}
+#endif
 
 	//clean up variant stack
 	for(int i=0;i<f->max_stack;i++) {
@@ -1679,6 +1763,7 @@ void VisualScriptInstance::create(const Ref<VisualScript>& p_script,Object *p_ow
 
 	script=p_script;
 	owner=p_owner;
+	source=p_script->get_path();
 
 	max_input_args = 0;
 	max_output_args = 0;
@@ -1697,7 +1782,7 @@ void VisualScriptInstance::create(const Ref<VisualScript>& p_script,Object *p_ow
 		function.node_count=0;
 
 		if (function.node<0) {
-			//@todo break debugger
+			VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(),0,"No start node in function: "+String(E->key()));
 
 			ERR_CONTINUE( function.node < 0 );
 		}
@@ -1705,7 +1790,10 @@ void VisualScriptInstance::create(const Ref<VisualScript>& p_script,Object *p_ow
 		{
 			Ref<VisualScriptFunction> func_node = script->get_node(E->key(),E->get().function_id);
 
-			//@todo break debugger
+			if (func_node.is_null()) {
+				VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(),0,"No VisualScriptFunction typed start node in function: "+String(E->key()));
+			}
+
 			ERR_CONTINUE( !func_node.is_valid() );
 
 			function.argument_count=func_node->get_argument_count();
@@ -1977,44 +2065,199 @@ void VisualScriptLanguage::add_global_constant(const StringName& p_variable,cons
 
 /* DEBUGGER FUNCTIONS */
 
+
+
+bool VisualScriptLanguage::debug_break_parse(const String& p_file, int p_node,const String& p_error) {
+	//break because of parse error
+
+    if (ScriptDebugger::get_singleton() && Thread::get_caller_ID()==Thread::get_main_ID()) {
+
+	_debug_parse_err_node=p_node;
+	_debug_parse_err_file=p_file;
+	_debug_error=p_error;
+	ScriptDebugger::get_singleton()->debug(this,false);
+	return true;
+    } else {
+	return false;
+    }
+
+}
+
+bool VisualScriptLanguage::debug_break(const String& p_error,bool p_allow_continue) {
+
+    if (ScriptDebugger::get_singleton() && Thread::get_caller_ID()==Thread::get_main_ID()) {
+
+	_debug_parse_err_node=-1;
+	_debug_parse_err_file="";
+	_debug_error=p_error;
+	ScriptDebugger::get_singleton()->debug(this,p_allow_continue);
+	return true;
+    } else {
+	return false;
+    }
+
+}
+
+
 String VisualScriptLanguage::debug_get_error() const {
 
-	return String();
+    return _debug_error;
 }
+
 int VisualScriptLanguage::debug_get_stack_level_count() const {
 
-	return 0;
+	if (_debug_parse_err_node>=0)
+		return 1;
+
+
+	return _debug_call_stack_pos;
 }
 int VisualScriptLanguage::debug_get_stack_level_line(int p_level) const {
 
-	return 0;
+	if (_debug_parse_err_node>=0)
+		return _debug_parse_err_node;
+
+    ERR_FAIL_INDEX_V(p_level,_debug_call_stack_pos,-1);
+
+    int l = _debug_call_stack_pos - p_level -1;
+
+    return *(_call_stack[l].current_id);
+
 }
 String VisualScriptLanguage::debug_get_stack_level_function(int p_level) const {
 
-	return String();
+	if (_debug_parse_err_node>=0)
+		return "";
+
+    ERR_FAIL_INDEX_V(p_level,_debug_call_stack_pos,"");
+    int l = _debug_call_stack_pos - p_level -1;
+    return *_call_stack[l].function;
 }
 String VisualScriptLanguage::debug_get_stack_level_source(int p_level) const {
 
-	return String();
+	if (_debug_parse_err_node>=0)
+		return _debug_parse_err_file;
+
+    ERR_FAIL_INDEX_V(p_level,_debug_call_stack_pos,"");
+    int l = _debug_call_stack_pos - p_level -1;
+    return _call_stack[l].instance->get_script_ptr()->get_path();
+
 }
 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) {
 
+	if (_debug_parse_err_node>=0)
+		return;
+
+	ERR_FAIL_INDEX(p_level,_debug_call_stack_pos);
+
+	int l = _debug_call_stack_pos - p_level -1;
+	const StringName *f = _call_stack[l].function;
+
+	ERR_FAIL_COND(!_call_stack[l].instance->functions.has(*f));
+	VisualScriptInstance::Function *func = &_call_stack[l].instance->functions[*f];
+
+	VisualScriptNodeInstance *node =_call_stack[l].instance->instances[*_call_stack[l].current_id];
+	ERR_FAIL_COND(!node);
+
+	p_locals->push_back("node_name");
+	p_values->push_back(node->get_base_node()->get_text());
+
+	for(int i=0;i<node->input_port_count;i++) {
+		String name = node->get_base_node()->get_input_value_port_info(i).name;
+		if (name==String()) {
+			name="in_"+itos(i);
+		}
+
+		p_locals->push_back("input/"+name);
+
+		//value is trickier
+
+		int in_from = node->input_ports[i];
+		int in_value = in_from&VisualScriptNodeInstance::INPUT_MASK;
+
+		if (in_from&VisualScriptNodeInstance::INPUT_DEFAULT_VALUE_BIT) {
+			p_values->push_back(_call_stack[l].instance->default_values[in_value]);
+		} else if (in_from&VisualScriptNodeInstance::INPUT_UNSEQUENCED_READ_BIT) {
+			p_values->push_back( _call_stack[l].stack[ func->unsequenced_gets[ in_value ].to_stack ] );
+		} else {
+			p_values->push_back( _call_stack[l].stack[ in_value] );
+		}
+	}
+
+	for(int i=0;i<node->output_port_count;i++) {
+
+		String name = node->get_base_node()->get_output_value_port_info(i).name;
+		if (name==String()) {
+			name="out_"+itos(i);
+		}
 
+		p_locals->push_back("output/"+name);
+
+		//value is trickier
+
+		int in_from = node->output_ports[i];
+		p_values->push_back( _call_stack[l].stack[ in_from] );
+
+	}
+
+	for(int i=0;i<node->get_working_memory_size();i++) {
+		p_locals->push_back("working_mem/mem_"+itos(i));
+		p_values->push_back( (*_call_stack[l].work_mem)[i]);
+	}
+
+/*
+    ERR_FAIL_INDEX(p_level,_debug_call_stack_pos);
+
+
+    VisualFunction *f = _call_stack[l].function;
+
+    List<Pair<StringName,int> > locals;
+
+    f->debug_get_stack_member_state(*_call_stack[l].line,&locals);
+    for( List<Pair<StringName,int> >::Element *E = locals.front();E;E=E->next() ) {
+
+	p_locals->push_back(E->get().first);
+	p_values->push_back(_call_stack[l].stack[E->get().second]);
+    }
+*/
 }
 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) {
 
+	if (_debug_parse_err_node>=0)
+		return;
+
+	ERR_FAIL_INDEX(p_level,_debug_call_stack_pos);
+	int l = _debug_call_stack_pos - p_level -1;
 
+
+	Ref<VisualScript> vs = _call_stack[l].instance->get_script();
+	if (vs.is_null())
+		return;
+
+	List<StringName> vars;
+	vs->get_variable_list(&vars);
+	for (List<StringName>::Element *E=vars.front();E;E=E->next()) {
+		Variant v;
+		if (_call_stack[l].instance->get_variable(E->get(),&v)) {
+			p_members->push_back("variables/"+E->get());
+			p_values->push_back(v);
+		}
+	}
 }
-void VisualScriptLanguage::debug_get_globals(List<String> *p_locals, 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) {
 
+    //no globals are really reachable in gdscript
 }
 String VisualScriptLanguage::debug_parse_stack_level_expression(int p_level,const String& p_expression,int p_max_subitems,int p_max_depth) {
 
-	return String();
+	if (_debug_parse_err_node>=0)
+		return "";
+	return "";
 }
 
 
+
 void VisualScriptLanguage::reload_all_scripts() {
 
 
@@ -2090,10 +2333,33 @@ VisualScriptLanguage::VisualScriptLanguage() {
 #ifndef NO_THREADS
 	lock = Mutex::create();
 #endif
+
+
+	_debug_parse_err_node=-1;
+	_debug_parse_err_file="";
+	_debug_call_stack_pos=0;
+	int dmcs=GLOBAL_DEF("debug/script_max_call_stack",1024);
+	if (ScriptDebugger::get_singleton()) {
+		//debugging enabled!
+		_debug_max_call_stack = dmcs;
+		if (_debug_max_call_stack<1024)
+			_debug_max_call_stack=1024;
+		_call_stack = memnew_arr( CallLevel, _debug_max_call_stack+1 );
+
+	} else {
+		_debug_max_call_stack=0;
+		_call_stack=NULL;
+	}
+
 }
 
 VisualScriptLanguage::~VisualScriptLanguage() {
 
 	if (lock)
 		memdelete(lock);
+
+	if (_call_stack)  {
+		memdelete_arr(_call_stack);
+	}
+	singleton=NULL;
 }

+ 78 - 4
modules/visual_script/visual_script.h

@@ -2,7 +2,7 @@
 #define VSCRIPT_H
 
 #include "script_language.h"
-
+#include "os/thread.h"
 
 class VisualScriptInstance;
 class VisualScriptNodeInstance;
@@ -16,6 +16,7 @@ friend class VisualScript;
 	Set<VisualScript*> scripts_used;
 
 	Array default_input_values;
+	bool breakpoint;
 
 	void _set_default_input_values(Array p_values);
 	Array _get_default_input_values() const;
@@ -47,14 +48,19 @@ public:
 	virtual String get_text() const=0;
 	virtual String get_category() const=0;
 
+	//used by editor, this is not really saved
+	void set_breakpoint(bool p_breakpoint);
+	bool is_breakpoint() const;
+
 	virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance)=0;
 
+	VisualScriptNode();
 };
 
 
 class VisualScriptNodeInstance {
 friend class VisualScriptInstance;
-
+friend class VisualScriptLanguage; //for debugger
 
 
 	enum { //input argument addressing
@@ -181,6 +187,8 @@ friend class VisualScriptInstance;
 
 		int function_id;
 
+		Vector2 scroll;
+
 
 		Function() { function_id=-1; }
 
@@ -225,12 +233,15 @@ public:
 	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 set_function_scroll(const StringName& p_name, const Vector2& p_scroll);
+	Vector2 get_function_scroll(const StringName& p_name) const;
 	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);
+	bool has_node(const StringName& p_func,int p_id) const;
 	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;
@@ -308,7 +319,6 @@ public:
 
 
 class VisualScriptInstance : public ScriptInstance {
-
 	Object *owner;
 	Ref<VisualScript> script;
 
@@ -340,9 +350,10 @@ class VisualScriptInstance : public ScriptInstance {
 	Vector<Variant> default_values;
 	int max_input_args,max_output_args;
 
+	StringName source;
 
 	//Map<StringName,Function> functions;
-
+friend class VisualScriptLanguage; //for debugger
 public:
 	virtual bool set(const StringName& p_name, const Variant& p_value);
 	virtual bool get(const StringName& p_name, Variant &r_ret) const;
@@ -396,6 +407,23 @@ class VisualScriptLanguage : public ScriptLanguage {
 
 	Map<String,VisualScriptNodeRegisterFunc> register_funcs;
 
+	struct CallLevel {
+
+	    Variant *stack;
+	    Variant **work_mem;
+	    const StringName *function;
+	    VisualScriptInstance *instance;
+	    int *current_id;
+
+	};
+
+
+	int _debug_parse_err_node;
+	String _debug_parse_err_file;
+	String _debug_error;
+	int _debug_call_stack_pos;
+	int _debug_max_call_stack;
+	CallLevel *_call_stack;
 
 public:
 	StringName notification;
@@ -404,6 +432,52 @@ public:
 
 	Mutex *lock;
 
+	bool debug_break(const String& p_error,bool p_allow_continue=true);
+	bool debug_break_parse(const String& p_file, int p_node,const String& p_error);
+
+	_FORCE_INLINE_ void enter_function(VisualScriptInstance *p_instance,const StringName* p_function, Variant *p_stack, Variant **p_work_mem,int *current_id) {
+
+	    if (Thread::get_main_ID()!=Thread::get_caller_ID())
+		return; //no support for other threads than main for now
+
+	    if (ScriptDebugger::get_singleton()->get_lines_left()>0 && ScriptDebugger::get_singleton()->get_depth()>=0)
+		ScriptDebugger::get_singleton()->set_depth( ScriptDebugger::get_singleton()->get_depth() +1 );
+
+	    if (_debug_call_stack_pos >= _debug_max_call_stack) {
+		//stack overflow
+		_debug_error="Stack Overflow (Stack Size: "+itos(_debug_max_call_stack)+")";
+		ScriptDebugger::get_singleton()->debug(this);
+		return;
+	    }
+
+	    _call_stack[_debug_call_stack_pos].stack=p_stack;
+	    _call_stack[_debug_call_stack_pos].instance=p_instance;
+	    _call_stack[_debug_call_stack_pos].function=p_function;
+	    _call_stack[_debug_call_stack_pos].work_mem=p_work_mem;
+	    _call_stack[_debug_call_stack_pos].current_id=current_id;
+	    _debug_call_stack_pos++;
+	}
+
+	_FORCE_INLINE_ void exit_function() {
+
+	    if (Thread::get_main_ID()!=Thread::get_caller_ID())
+		return; //no support for other threads than main for now
+
+	    if (ScriptDebugger::get_singleton()->get_lines_left()>0 && ScriptDebugger::get_singleton()->get_depth()>=0)
+		ScriptDebugger::get_singleton()->set_depth( ScriptDebugger::get_singleton()->get_depth() -1 );
+
+	    if (_debug_call_stack_pos==0) {
+
+		_debug_error="Stack Underflow (Engine Bug)";
+		ScriptDebugger::get_singleton()->debug(this);
+		return;
+	    }
+
+	    _debug_call_stack_pos--;
+	}
+
+	//////////////////////////////////////
+
 	virtual String get_name() const;
 
 	/* LANGUAGE FUNCTIONS */

+ 241 - 11
modules/visual_script/visual_script_editor.cpp

@@ -347,6 +347,8 @@ void VisualScriptEditor::_update_graph_connections() {
 void VisualScriptEditor::_update_graph(int p_only_id) {
 
 
+	updating_graph=true;
+
 	//byebye all nodes
 	if (p_only_id>=0) {
 		if (graph->has_node(itos(p_only_id))) {
@@ -368,6 +370,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
 	if (!script->has_function(edited_func)) {
 		graph->hide();
 		select_func_text->show();
+		updating_graph=false;
 		return;
 	}
 
@@ -424,9 +427,14 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
 
 		GraphNode *gnode = memnew( GraphNode );
 		gnode->set_title(node->get_caption());
+		if (error_line==E->get()) {
+			gnode->set_overlay(GraphNode::OVERLAY_POSITION);
+		} else if (node->is_breakpoint()) {
+			gnode->set_overlay(GraphNode::OVERLAY_BREAKPOINT);
+		}
 
-		if (EditorSettings::get_singleton()->has("visual_script/color_"+node->get_category())) {
-			gnode->set_modulate(EditorSettings::get_singleton()->get("visual_script/color_"+node->get_category()));
+		if (EditorSettings::get_singleton()->has("visual_script_editor/color_"+node->get_category())) {
+			gnode->set_modulate(EditorSettings::get_singleton()->get("visual_script_editor/color_"+node->get_category()));
 		}
 
 		gnode->set_meta("__vnode",node);
@@ -555,6 +563,8 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
 	}
 
 	_update_graph_connections();
+	graph->call_deferred("set_scroll_ofs",script->get_function_scroll(edited_func)*EDSCALE); //may need to adapt a bit, let it do so
+	updating_graph=false;
 
 }
 
@@ -583,6 +593,10 @@ void VisualScriptEditor::_update_members() {
 		//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 (E->get()==edited_func) {
+			ti->set_custom_bg_color(0,get_color("prop_category","Editor"));
+			ti->set_custom_color(0,Color(1,1,1,1));
+		}
 		if (selected==E->get())
 			ti->select(0);
 	}
@@ -660,6 +674,7 @@ void VisualScriptEditor::_member_selected() {
 
 			revert_on_drag=edited_func;
 			edited_func=selected;
+			_update_members();
 			_update_graph();
 		}
 
@@ -1804,23 +1819,91 @@ Ref<Texture> VisualScriptEditor::get_icon(){
 }
 
 bool VisualScriptEditor::is_unsaved(){
-
+#ifdef TOOLS_ENABLED
+	return script->is_edited();
+#else
 	return false;
+#endif
 }
 
 Variant VisualScriptEditor::get_edit_state(){
 
-	return Variant();
+	Dictionary d;
+	d["function"]=edited_func;
+	d["scroll"]=graph->get_scroll_ofs();
+	d["zoom"]=graph->get_zoom();
+	d["using_snap"]=graph->is_using_snap();
+	d["snap"]=graph->get_snap();
+	return d;
 }
 
 void VisualScriptEditor::set_edit_state(const Variant& p_state){
 
+	Dictionary d = p_state;
+	if (d.has("function")) {
+		edited_func=p_state;
+		selected=edited_func;
+
+	}
+
+	_update_graph();
+	_update_members();
+
+	if (d.has("scroll")) {
+		graph->set_scroll_ofs(d["scroll"]);
+	}
+	if (d.has("zoom")) {
+		graph->set_zoom(d["zoom"]);
+	}
+	if (d.has("snap")) {
+		graph->set_snap(d["snap"]);
+	}
+	if (d.has("snap_enabled")) {
+		graph->set_use_snap(d["snap_enabled"]);
+	}
 
 }
 
-void VisualScriptEditor::goto_line(int p_line){
 
+void VisualScriptEditor::_center_on_node(int p_id) {
+
+	Node *n = graph->get_node(itos(p_id));
+	if (!n)
+		return;
+	GraphNode *gn = n->cast_to<GraphNode>();
+	if (gn) {
+		gn->set_selected(true);
+		Vector2 new_scroll = gn->get_offset() - graph->get_size()*0.5 + gn->get_size()*0.5;
+		graph->set_scroll_ofs( new_scroll );
+		script->set_function_scroll(edited_func,new_scroll/EDSCALE);
+		script->set_edited(true); //so it's saved
 
+	}
+}
+
+void VisualScriptEditor::goto_line(int p_line, bool p_with_error){
+
+	p_line+=1; //add one because script lines begin from 0.
+
+	if (p_with_error)
+		error_line=p_line;
+
+	List<StringName> functions;
+	script->get_function_list(&functions);
+	for (List<StringName>::Element *E=functions.front();E;E=E->next()) {
+
+		if (script->has_node(E->get(),p_line)) {
+
+			edited_func=E->get();
+			selected=edited_func;
+			_update_graph();
+			_update_members();
+
+			call_deferred("_center_on_node",p_line); //editor might be just created and size might not exist yet
+
+			return;
+		}
+	}
 }
 
 void VisualScriptEditor::trim_trailing_whitespace(){
@@ -1830,7 +1913,7 @@ void VisualScriptEditor::trim_trailing_whitespace(){
 
 void VisualScriptEditor::ensure_focus(){
 
-
+	graph->grab_focus();
 }
 
 void VisualScriptEditor::tag_saved_version(){
@@ -1845,24 +1928,92 @@ void VisualScriptEditor::reload(bool p_soft){
 
 void VisualScriptEditor::get_breakpoints(List<int> *p_breakpoints){
 
+	List<StringName> functions;
+	script->get_function_list(&functions);
+	for (List<StringName>::Element *E=functions.front();E;E=E->next()) {
+
+		List<int> nodes;
+		script->get_node_list(E->get(),&nodes);
+		for (List<int>::Element *F=nodes.front();F;F=F->next()) {
 
+			Ref<VisualScriptNode> vsn = script->get_node(E->get(),F->get());
+			if (vsn->is_breakpoint()) {
+				p_breakpoints->push_back(F->get()-1); //subtract 1 because breakpoints in text start from zero
+			}
+		}
+	}
 }
 
 bool VisualScriptEditor::goto_method(const String& p_method){
 
-	return false;
+	if (!script->has_function(p_method))
+		return false;
+
+	edited_func=p_method;
+	selected=edited_func;
+	_update_members();
+	_update_graph();
+	return true;
 }
 
 void VisualScriptEditor::add_callback(const String& p_function,StringArray p_args){
 
+	if (script->has_function(p_function)) {
+		edited_func=p_function;
+		selected=edited_func;
+		_update_members();
+		_update_graph();
+		return;
+	}
+
+	Ref<VisualScriptFunction> func;
+	func.instance();
+	for(int i=0;i<p_args.size();i++) {
+
+		String name = p_args[i];
+		Variant::Type type=Variant::NIL;
+
+		if (name.find(":")!=-1) {
+			String tt = name.get_slice(":",1);
+			name=name.get_slice(":",0);
+			for(int j=0;j<Variant::VARIANT_MAX;j++) {
+
+				String tname = Variant::get_type_name(Variant::Type(j));
+				if (tname==tt) {
+					type=Variant::Type(j);
+					break;
+				}
+			}
+		}
+
+		func->add_argument(type,name);
+	}
+
+	func->set_name(p_function);
+	script->add_function(p_function);
+	script->add_node(p_function,script->get_available_id(),func);
+
+	edited_func=p_function;
+	selected=edited_func;
+	_update_members();
+	_update_graph();
+	graph->call_deferred("set_scroll_ofs",script->get_function_scroll(edited_func)); //for first time it might need to be later
+
+	//undo_redo->clear_history();
 
 }
 
 void VisualScriptEditor::update_settings(){
 
-
+	_update_graph();
 }
 
+void VisualScriptEditor::set_debugger_active(bool p_active) {
+	if (!p_active) {
+		error_line=-1;
+		_update_graph(); //clear line break
+	}
+}
 
 void VisualScriptEditor::set_tooltip_request_func(String p_method,Object* p_obj){
 
@@ -1871,7 +2022,7 @@ void VisualScriptEditor::set_tooltip_request_func(String p_method,Object* p_obj)
 
 Control *VisualScriptEditor::get_edit_menu(){
 
-	return NULL;
+	return edit_menu;
 }
 
 void VisualScriptEditor::_change_base_type() {
@@ -2166,6 +2317,55 @@ void  VisualScriptEditor::_notification(int p_what) {
 	}
 }
 
+void VisualScriptEditor::_graph_ofs_changed(const Vector2& p_ofs) {
+
+	if (updating_graph)
+		return;
+
+	updating_graph=true;
+
+	if (script->has_function(edited_func)) {
+		script->set_function_scroll(edited_func,graph->get_scroll_ofs()/EDSCALE);
+		script->set_edited(true);
+	}
+	updating_graph=false;
+}
+
+void VisualScriptEditor::_menu_option(int p_what) {
+
+	switch(p_what) {
+		case EDIT_DELETE_NODES: {
+			_on_nodes_delete();
+		} break;
+		case EDIT_TOGGLE_BREAKPOINT: {
+
+			List<String> reselect;
+			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> vsn = script->get_node(edited_func,id);
+						if (vsn.is_valid()) {
+							vsn->set_breakpoint(!vsn->is_breakpoint());
+							reselect.push_back(gn->get_name());
+						}
+					}
+				}
+			}
+
+			_update_graph();
+
+			for(List<String>::Element *E=reselect.front();E;E=E->next()) {
+				GraphNode *gn = graph->get_node(E->get())->cast_to<GraphNode>();
+				gn->set_selected(true);
+			}
+
+		} break;
+
+	}
+}
+
 void VisualScriptEditor::_bind_methods() {
 
 	ObjectTypeDB::bind_method("_member_button",&VisualScriptEditor::_member_button);
@@ -2186,6 +2386,9 @@ void VisualScriptEditor::_bind_methods() {
 	ObjectTypeDB::bind_method("_available_node_doubleclicked",&VisualScriptEditor::_available_node_doubleclicked);
 	ObjectTypeDB::bind_method("_default_value_edited",&VisualScriptEditor::_default_value_edited);
 	ObjectTypeDB::bind_method("_default_value_changed",&VisualScriptEditor::_default_value_changed);
+	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);
 
 
 
@@ -2211,6 +2414,14 @@ void VisualScriptEditor::_bind_methods() {
 
 VisualScriptEditor::VisualScriptEditor() {
 
+	updating_graph=false;
+
+	edit_menu = memnew( MenuButton );
+	edit_menu->set_text(TTR("Edit"));
+	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()->connect("item_pressed",this,"_menu_option");
+
 	main_hsplit = memnew( HSplitContainer );
 	add_child(main_hsplit);
 	main_hsplit->set_area_as_parent_rect();
@@ -2232,7 +2443,7 @@ VisualScriptEditor::VisualScriptEditor() {
 	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->connect("cell_selected",this,"_member_selected",varray(),CONNECT_DEFERRED);
 	members->set_single_select_cell_editing_only_when_already_selected(true);
 	members->set_hide_folding(true);
 	members->set_drag_forwarding(this);
@@ -2274,6 +2485,7 @@ VisualScriptEditor::VisualScriptEditor() {
 	graph->connect("duplicate_nodes_request",this,"_on_nodes_duplicate");
 	graph->set_drag_forwarding(this);
 	graph->hide();
+	graph->connect("scroll_offset_changed",this,"_graph_ofs_changed");
 
 	select_func_text = memnew( Label );
 	select_func_text->set_text(TTR("Select or create a function to edit graph"));
@@ -2358,6 +2570,7 @@ VisualScriptEditor::VisualScriptEditor() {
 	add_child(default_value_edit);
 	default_value_edit->connect("variant_changed",this,"_default_value_changed");
 
+	error_line=-1;
 }
 
 VisualScriptEditor::~VisualScriptEditor() {
@@ -2376,9 +2589,26 @@ static ScriptEditorBase * create_editor(const Ref<Script>& p_script) {
 	return NULL;
 }
 
+static void register_editor_callback() {
+
+	ScriptEditor::register_create_script_editor_function(create_editor);
+	EditorSettings::get_singleton()->set("visual_script_editor/color_functions",Color(1,0.9,0.9));
+	EditorSettings::get_singleton()->set("visual_script_editor/color_data",Color(0.9,1.0,0.9));
+	EditorSettings::get_singleton()->set("visual_script_editor/color_operators",Color(0.9,0.9,1.0));
+	EditorSettings::get_singleton()->set("visual_script_editor/color_flow_control",Color(1.0,1.0,0.8));
+
+
+	ED_SHORTCUT("visual_script_editor/delete_selected", TTR("Delete Selected"));
+	ED_SHORTCUT("visual_script_editor/toggle_breakpoint", TTR("Toggle Breakpoint"), KEY_F9);
+
+}
 
 void VisualScriptEditor::register_editor() {
 
-	ScriptEditor::register_create_script_editor_function(create_editor);
+	//too early to register stuff here, request a callback
+	EditorNode::add_plugin_init_callback(register_editor_callback);
+
+
+
 }
 

+ 18 - 2
modules/visual_script/visual_script_editor.h

@@ -22,6 +22,13 @@ class VisualScriptEditor : public ScriptEditorBase {
 
 	};
 
+	enum {
+		EDIT_DELETE_NODES,
+		EDIT_TOGGLE_BREAKPOINT
+	};
+
+	MenuButton *edit_menu;
+
 	Ref<VisualScript> script;
 
 	Button *base_type_select;
@@ -57,6 +64,8 @@ class VisualScriptEditor : public ScriptEditorBase {
 
 	Label *select_func_text;
 
+	bool updating_graph;
+
 	void _show_hint(const String& p_hint);
 	void _hide_timer();
 
@@ -88,7 +97,10 @@ class VisualScriptEditor : public ScriptEditorBase {
 	String _validate_name(const String& p_name) const;
 
 
+	int error_line;
+
 	void _node_selected(Node* p_node);
+	void _center_on_node(int p_id);
 
 	void _node_filter_changed(const String& p_text);
 	void _change_base_type_callback();
@@ -129,6 +141,10 @@ class VisualScriptEditor : public ScriptEditorBase {
 
 	void _default_value_changed();
 	void _default_value_edited(Node * p_button,int p_id,int p_input_port);
+
+	void _menu_option(int p_what);
+
+	void _graph_ofs_changed(const Vector2& p_ofs);
 protected:
 
 	void _notification(int p_what);
@@ -145,7 +161,7 @@ public:
 	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 goto_line(int p_line,bool p_with_error=false);
 	virtual void trim_trailing_whitespace();
 	virtual void ensure_focus();
 	virtual void tag_saved_version();
@@ -154,7 +170,7 @@ public:
 	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_debugger_active(bool p_active);
 	virtual void set_tooltip_request_func(String p_method,Object* p_obj);
 	virtual Control *get_edit_menu();
 

+ 6 - 0
modules/visual_script/visual_script_nodes.cpp

@@ -529,9 +529,15 @@ public:
 		}
 
 		if (!valid) {
+
 			r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
 			if (p_outputs[0]->get_type()==Variant::STRING) {
 				r_error_str=*p_outputs[0];
+			} else {
+				if (unary)
+					r_error_str=String(op_names[op])+RTR(": Invalid argument of type: ")+Variant::get_type_name(p_inputs[0]->get_type());
+				else
+					r_error_str=String(op_names[op])+RTR(": Invalid arguments: ")+"A: "+Variant::get_type_name(p_inputs[0]->get_type())+"  B: "+Variant::get_type_name(p_inputs[1]->get_type());
 			}
 		}
 

+ 23 - 1
scene/gui/graph_edit.cpp

@@ -100,6 +100,15 @@ void GraphEdit::get_connection_list(List<Connection> *r_connections) const {
 	*r_connections=connections;
 }
 
+void GraphEdit::set_scroll_ofs(const Vector2& p_ofs) {
+
+	setting_scroll_ofs=true;
+	h_scroll->set_val(p_ofs.x);
+	v_scroll->set_val(p_ofs.y);
+	_update_scroll();
+	setting_scroll_ofs=false;
+}
+
 Vector2 GraphEdit::get_scroll_ofs() const{
 
 	return Vector2(h_scroll->get_val(),v_scroll->get_val());
@@ -113,6 +122,10 @@ void GraphEdit::_scroll_moved(double) {
 		//must redraw grid
 		update();
 	}
+
+	if (!setting_scroll_ofs) {//in godot, signals on change value are avoided as a convention
+		emit_signal("scroll_offset_changed",get_scroll_ofs());
+	}
 }
 
 void GraphEdit::_update_scroll_offset() {
@@ -1042,6 +1055,7 @@ void GraphEdit::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("disconnect_node","from","from_port","to","to_port"),&GraphEdit::disconnect_node);
 	ObjectTypeDB::bind_method(_MD("get_connection_list"),&GraphEdit::_get_connection_list);
 	ObjectTypeDB::bind_method(_MD("get_scroll_ofs"),&GraphEdit::get_scroll_ofs);
+	ObjectTypeDB::bind_method(_MD("set_scroll_ofs","ofs"),&GraphEdit::set_scroll_ofs);
 
 	ObjectTypeDB::bind_method(_MD("set_zoom","p_zoom"),&GraphEdit::set_zoom);
 	ObjectTypeDB::bind_method(_MD("get_zoom"),&GraphEdit::get_zoom);
@@ -1079,6 +1093,7 @@ void GraphEdit::_bind_methods() {
 	ADD_SIGNAL(MethodInfo("delete_nodes_request"));
 	ADD_SIGNAL(MethodInfo("_begin_node_move"));
 	ADD_SIGNAL(MethodInfo("_end_node_move"));
+	ADD_SIGNAL(MethodInfo("scroll_offset_changed",PropertyInfo(Variant::VECTOR2,"ofs")));
 }
 
 
@@ -1109,6 +1124,13 @@ GraphEdit::GraphEdit() {
 	box_selecting = false;
 	dragging = false;
 
+	//set large minmax so it can scroll even if not resized yet
+	h_scroll->set_min(-10000);
+	h_scroll->set_max(10000);
+
+	v_scroll->set_min(-10000);
+	v_scroll->set_max(10000);
+
 	h_scroll->connect("value_changed", this,"_scroll_moved");
 	v_scroll->connect("value_changed", this,"_scroll_moved");
 
@@ -1149,6 +1171,6 @@ GraphEdit::GraphEdit() {
 	snap_amount->connect("value_changed",this,"_snap_value_changed");
 	zoom_hb->add_child(snap_amount);
 
-
+	setting_scroll_ofs=false;
 
 }

+ 2 - 0
scene/gui/graph_edit.h

@@ -107,6 +107,7 @@ private:
 	Rect2 box_selecting_rect;
 	List<GraphNode*> previus_selected;
 
+	bool setting_scroll_ofs;
 	bool right_disconnects;
 	bool updating;
 	List<Connection> connections;
@@ -188,6 +189,7 @@ public:
 	void add_valid_left_disconnect_type(int p_type);
 	void remove_valid_left_disconnect_type(int p_type);
 
+	void set_scroll_ofs(const Vector2& p_ofs);
 	Vector2 get_scroll_ofs() const;
 
 	void set_selected(Node* p_child);

+ 33 - 0
scene/gui/graph_node.cpp

@@ -205,6 +205,20 @@ void GraphNode::_notification(int p_what) {
 
 		draw_style_box(sb,Rect2(Point2(),get_size()));
 
+		switch(overlay) {
+			case OVERLAY_DISABLED: {
+
+			} break;
+			case OVERLAY_BREAKPOINT: {
+
+				draw_style_box(get_stylebox("breakpoint"),Rect2(Point2(),get_size()));
+			} break;
+			case OVERLAY_POSITION: {
+				draw_style_box(get_stylebox("position"),Rect2(Point2(),get_size()));
+
+			} break;
+		}
+
 		int w = get_size().width-sb->get_minimum_size().x;
 
 		if (show_close)
@@ -605,6 +619,16 @@ Color GraphNode::get_modulate() const{
 
 	return modulate;
 }
+void GraphNode::set_overlay(Overlay p_overlay) {
+
+	overlay=p_overlay;
+	update();
+}
+
+GraphNode::Overlay GraphNode::get_overlay() const{
+
+	return overlay;
+}
 
 void GraphNode::_bind_methods() {
 
@@ -641,6 +665,9 @@ void GraphNode::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("set_show_close_button","show"),&GraphNode::set_show_close_button);
 	ObjectTypeDB::bind_method(_MD("is_close_button_visible"),&GraphNode::is_close_button_visible);
 
+	ObjectTypeDB::bind_method(_MD("set_overlay","overlay"),&GraphNode::set_overlay);
+	ObjectTypeDB::bind_method(_MD("get_overlay"),&GraphNode::get_overlay);
+
 	ADD_PROPERTY( PropertyInfo(Variant::STRING,"title"),_SCS("set_title"),_SCS("get_title"));
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"show_close"),_SCS("set_show_close_button"),_SCS("is_close_button_visible"));
 
@@ -648,9 +675,15 @@ 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"));
+
+	BIND_CONSTANT( OVERLAY_DISABLED );
+	BIND_CONSTANT( OVERLAY_BREAKPOINT );
+	BIND_CONSTANT( OVERLAY_POSITION );
 }
 
 GraphNode::GraphNode() {
+
+	overlay=OVERLAY_DISABLED;
 	show_close=false;
 	connpos_dirty=true;
 	set_stop_mouse(false);

+ 13 - 1
scene/gui/graph_node.h

@@ -34,8 +34,14 @@
 class GraphNode : public Container {
 
 	OBJ_TYPE(GraphNode,Container);
+public:
 
-
+	enum Overlay {
+		OVERLAY_DISABLED,
+		OVERLAY_BREAKPOINT,
+		OVERLAY_POSITION
+	};
+private:
 
 	struct Slot {
 		bool enable_left;
@@ -78,6 +84,8 @@ class GraphNode : public Container {
 	Vector2 drag_from;
 	bool selected;
 
+	Overlay overlay;
+
 	Color modulate;
 protected:
 
@@ -133,10 +141,14 @@ public:
 	void set_modulate(const Color& p_color);
 	Color get_modulate() const;
 
+	void set_overlay(Overlay p_overlay);
+	Overlay get_overlay() const;
+
 	virtual Size2 get_minimum_size() const;
 
 	GraphNode();
 };
 
+VARIANT_ENUM_CAST( GraphNode::Overlay )
 
 #endif // GRAPH_NODE_H

+ 2 - 2
scene/gui/text_edit.h

@@ -438,7 +438,7 @@ public:
 	bool is_highlight_all_occurrences_enabled() const;
 	bool is_selection_active() const;
 	int get_selection_from_line() const;
-    int get_selection_from_column() const;
+	int get_selection_from_column() const;
 	int get_selection_to_line() const;
 	int get_selection_to_column() const;
 	String get_selection_text() const;
@@ -496,7 +496,7 @@ public:
 
 	String get_text_for_completion();
 
-    virtual bool is_text_field() const;
+	virtual bool is_text_field() const;
 	TextEdit();
 	~TextEdit();
 };

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

@@ -630,12 +630,17 @@ void fill_default_theme(Ref<Theme>& t,const Ref<Font> & default_font,const Ref<F
 	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);
+	Ref<StyleBoxTexture> graph_bpoint = make_stylebox(graph_node_breakpoint_png,6,24,6,5,16,24,16,5);
+	Ref<StyleBoxTexture> graph_position = make_stylebox(graph_node_position_png,6,24,6,5,16,24,16,5);
+
 	//graphsb->set_expand_margin_size(MARGIN_LEFT,10);
 	//graphsb->set_expand_margin_size(MARGIN_RIGHT,10);
 	t->set_stylebox("frame","GraphNode", graphsb );
 	t->set_stylebox("selectedframe","GraphNode", graphsbselected );
 	t->set_stylebox("defaultframe", "GraphNode", graphsbdefault );
 	t->set_stylebox("defaultfocus", "GraphNode", graphsbdeffocus );
+	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 ) );

二進制
scene/resources/default_theme/graph_node_breakpoint.png


二進制
scene/resources/default_theme/graph_node_position.png


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


文件差異過大導致無法顯示
+ 10 - 0
scene/resources/default_theme/theme_data.h


+ 1 - 1
tools/editor/connections_dialog.cpp

@@ -674,7 +674,7 @@ void ConnectionsDock::update_tree() {
 						tname=Variant::get_type_name(pi.type);
 					}
 					signaldesc+=tname+" "+(pi.name==""?String("arg "+itos(i)):pi.name);
-					argnames.push_back(pi.name);
+					argnames.push_back(pi.name+":"+tname);
 
 				}
 				signaldesc+=" ";

+ 16 - 0
tools/editor/editor_node.cpp

@@ -5220,6 +5220,17 @@ void EditorNode::reload_scene(const String& p_path) {
 	_scene_tab_changed(current_tab);
 }
 
+int EditorNode::plugin_init_callback_count=0;
+
+void EditorNode::add_plugin_init_callback(EditorPluginInitializeCallback p_callback) {
+
+	ERR_FAIL_COND(plugin_init_callback_count==MAX_INIT_CALLBACKS);
+
+	plugin_init_callbacks[plugin_init_callback_count++]=p_callback;
+}
+
+EditorPluginInitializeCallback EditorNode::plugin_init_callbacks[EditorNode::MAX_INIT_CALLBACKS];
+
 
 void EditorNode::_bind_methods() {
 
@@ -6499,6 +6510,9 @@ EditorNode::EditorNode() {
 	for(int i=0;i<EditorPlugins::get_plugin_count();i++)
 		add_editor_plugin( EditorPlugins::create(i,this) );
 
+	for(int i=0;i<plugin_init_callback_count;i++) {
+		plugin_init_callbacks[i]();
+	}
 
 	resource_preview->add_preview_generator( Ref<EditorTexturePreviewPlugin>( memnew(EditorTexturePreviewPlugin )));
 	resource_preview->add_preview_generator( Ref<EditorPackedScenePreviewPlugin>( memnew(EditorPackedScenePreviewPlugin )));
@@ -6508,6 +6522,8 @@ EditorNode::EditorNode() {
 	resource_preview->add_preview_generator( Ref<EditorMeshPreviewPlugin>( memnew(EditorMeshPreviewPlugin )));
 	resource_preview->add_preview_generator( Ref<EditorBitmapPreviewPlugin>( memnew(EditorBitmapPreviewPlugin )));
 
+
+
 	circle_step_msec=OS::get_singleton()->get_ticks_msec();
 	circle_step_frame=OS::get_singleton()->get_frames_drawn();
 	circle_step=0;

+ 12 - 0
tools/editor/editor_node.h

@@ -94,6 +94,7 @@
 
 
 typedef void (*EditorNodeInitCallback)();
+typedef void (*EditorPluginInitializeCallback)();
 
 class EditorPluginList;
 
@@ -575,11 +576,20 @@ private:
 
 	static void _file_access_close_error_notify(const String& p_str);
 
+
+	enum {
+		MAX_INIT_CALLBACKS=128
+	};
+
+	static int plugin_init_callback_count;
+	static EditorPluginInitializeCallback plugin_init_callbacks[MAX_INIT_CALLBACKS];
 protected:
 	void _notification(int p_what);
 	static void _bind_methods();
 public:
 
+	static void add_plugin_init_callback(EditorPluginInitializeCallback p_callback);
+
 	enum EditorTable {
 		EDITOR_2D = 0,
 		EDITOR_3D,
@@ -741,6 +751,8 @@ public:
 
 	static void add_init_callback(EditorNodeInitCallback p_callback) { _init_callbacks.push_back(p_callback); }
 
+
+
 };
 
 

+ 0 - 5
tools/editor/editor_settings.cpp

@@ -647,11 +647,6 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
 
 	set("import/automatic_reimport_on_sources_changed",true);
 
-	set("visual_script/color_functions",Color(1,0.9,0.9));
-	set("visual_script/color_data",Color(0.9,1.0,0.9));
-	set("visual_script/color_operators",Color(0.9,0.9,1.0));
-	set("visual_script/color_flow_control",Color(1.0,1.0,0.8));
-
 	if (p_extra_config.is_valid()) {
 
 		if (p_extra_config->has_section("init_projects") && p_extra_config->has_section_key("init_projects", "list")) {

+ 35 - 1
tools/editor/plugins/script_editor_plugin.cpp

@@ -285,6 +285,17 @@ void ScriptEditor::_breaked(bool p_breaked,bool p_can_debug) {
 	debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_BREAK), p_breaked );
 	debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_CONTINUE), !p_breaked );
 
+	for(int i=0;i<tab_container->get_child_count();i++) {
+
+		ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>();
+		if (!se) {
+
+			continue;
+		}
+
+		se->set_debugger_active(p_breaked);
+	}
+
 }
 
 void ScriptEditor::_show_debugger(bool p_show) {
@@ -315,7 +326,16 @@ void ScriptEditor::_goto_script_line(REF p_script,int p_line) {
 
 
 	editor->push_item(p_script.ptr());
-	_goto_script_line2(p_line);
+
+	int selected = tab_container->get_current_tab();
+	if (selected<0 || selected>=tab_container->get_child_count())
+		return;
+
+	ScriptEditorBase *current = tab_container->get_child(selected)->cast_to<ScriptEditorBase>();
+	if (!current)
+		return;
+
+	current->goto_line(p_line,true);
 
 }
 
@@ -1133,6 +1153,7 @@ void ScriptEditor::clear() {
 
 void ScriptEditor::get_breakpoints(List<String> *p_breakpoints) {
 
+
 	for(int i=0;i<tab_container->get_child_count();i++) {
 
 		ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>();
@@ -1500,6 +1521,8 @@ void ScriptEditor::save_all_scripts() {
 
 	}
 
+	_update_script_names();
+
 }
 
 void ScriptEditor::apply_scripts() const {
@@ -1536,6 +1559,17 @@ void ScriptEditor::_editor_stop() {
 	debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_STEP), true );
 	debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_BREAK), true );
 	debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_CONTINUE), true );
+
+	for(int i=0;i<tab_container->get_child_count();i++) {
+
+		ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>();
+		if (!se) {
+
+			continue;
+		}
+
+		se->set_debugger_active(false);
+	}
 }
 
 

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

@@ -91,7 +91,7 @@ public:
 	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 goto_line(int p_line,bool p_with_error=false)=0;
 	virtual void trim_trailing_whitespace()=0;
 	virtual void ensure_focus()=0;
 	virtual void tag_saved_version()=0;
@@ -100,6 +100,7 @@ public:
 	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_debugger_active(bool p_active)=0;
 
 	virtual void set_tooltip_request_func(String p_method,Object* p_obj)=0;
 	virtual Control *get_edit_menu()=0;

+ 6 - 1
tools/editor/plugins/script_text_editor.cpp

@@ -312,7 +312,7 @@ void ScriptTextEditor::tag_saved_version() {
 	code_editor->get_text_edit()->tag_saved_version();
 }
 
-void ScriptTextEditor::goto_line(int p_line) {
+void ScriptTextEditor::goto_line(int p_line, bool p_with_error) {
 	code_editor->get_text_edit()->cursor_set_line(p_line);
 }
 
@@ -952,6 +952,11 @@ 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);
 }
 
+void ScriptTextEditor::set_debugger_active(bool p_active) {
+
+
+}
+
 ScriptTextEditor::ScriptTextEditor() {
 
 	code_editor = memnew( CodeTextEditor );

+ 3 - 1
tools/editor/plugins/script_text_editor.h

@@ -115,7 +115,7 @@ public:
 	virtual void trim_trailing_whitespace();
 	virtual void tag_saved_version();
 
-	virtual void goto_line(int p_line);
+	virtual void goto_line(int p_line,bool p_with_error=false);
 
 	virtual void reload(bool p_soft);
 	virtual void get_breakpoints(List<int> *p_breakpoints);
@@ -126,6 +126,8 @@ public:
 
 	virtual void set_tooltip_request_func(String p_method,Object* p_obj);
 
+	virtual void set_debugger_active(bool p_active);
+
 	Control *get_edit_menu();
 
 	static void register_editor();

+ 2 - 1
tools/editor/script_editor_debugger.cpp

@@ -220,6 +220,7 @@ void ScriptEditorDebugger::debug_continue() {
 	msg.push_back("continue");
 	ppeer->put_var(msg);
 
+
 }
 
 void ScriptEditorDebugger::_scene_tree_folded(Object* obj) {
@@ -360,7 +361,7 @@ void ScriptEditorDebugger::_parse_message(const String& p_msg,const Array& p_dat
 		forward->set_disabled(true);
 		dobreak->set_disabled(false);
 		docontinue->set_disabled(true);
-		emit_signal("breaked",false,false);
+		emit_signal("breaked",false,false,Variant());
 		//tabs->set_current_tab(0);
 		profiler->set_enabled(true);
 		profiler->disable_seeking();

部分文件因文件數量過多而無法顯示