diff options
author | Juan Linietsky <reduzio@gmail.com> | 2016-08-06 19:00:54 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2016-08-06 19:00:54 -0300 |
commit | 9890c1d2ca76dc936e23f5263a4fd296bfc68996 (patch) | |
tree | be0d304ab3f3b19e3460eee5e0bbdf68d0028f12 /modules | |
parent | 259418f8275371fc2f0bab6892caa4ef66b84240 (diff) |
Likely with bugs and with some features are missing, as well as profiler support, but VisualScript should be more or less done!
Diffstat (limited to 'modules')
-rw-r--r-- | modules/gdscript/gd_editor.cpp | 2 | ||||
-rw-r--r-- | modules/visual_script/visual_script.cpp | 300 | ||||
-rw-r--r-- | modules/visual_script/visual_script.h | 82 | ||||
-rw-r--r-- | modules/visual_script/visual_script_editor.cpp | 252 | ||||
-rw-r--r-- | modules/visual_script/visual_script_editor.h | 20 | ||||
-rw-r--r-- | modules/visual_script/visual_script_nodes.cpp | 6 |
6 files changed, 627 insertions, 35 deletions
diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp index b3ab75b07c..48f747ada9 100644 --- a/modules/gdscript/gd_editor.cpp +++ b/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+=" "; } diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index 5fc5e8a9fc..7c94e41331 100644 --- a/modules/visual_script/visual_script.cpp +++ b/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,¤t_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; } diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h index c606604649..ddd215fb9c 100644 --- a/modules/visual_script/visual_script.h +++ b/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 */ diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index b9eb76862e..0407a37a7b 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/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); + + + } diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h index 61a486da02..22dc6ce87f 100644 --- a/modules/visual_script/visual_script_editor.h +++ b/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(); diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp index ed7119e27a..8362cdd671 100644 --- a/modules/visual_script/visual_script_nodes.cpp +++ b/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()); } } |