diff options
Diffstat (limited to 'modules/visual_script')
-rw-r--r-- | modules/visual_script/register_types.cpp | 14 | ||||
-rw-r--r-- | modules/visual_script/visual_script.cpp | 1402 | ||||
-rw-r--r-- | modules/visual_script/visual_script.h | 286 | ||||
-rw-r--r-- | modules/visual_script/visual_script_builtin_funcs.cpp | 672 | ||||
-rw-r--r-- | modules/visual_script/visual_script_builtin_funcs.h | 3 | ||||
-rw-r--r-- | modules/visual_script/visual_script_editor.cpp | 291 | ||||
-rw-r--r-- | modules/visual_script/visual_script_editor.h | 21 | ||||
-rw-r--r-- | modules/visual_script/visual_script_flow_control.cpp | 1284 | ||||
-rw-r--r-- | modules/visual_script/visual_script_flow_control.h | 94 | ||||
-rw-r--r-- | modules/visual_script/visual_script_func_nodes.cpp | 695 | ||||
-rw-r--r-- | modules/visual_script/visual_script_func_nodes.h | 29 | ||||
-rw-r--r-- | modules/visual_script/visual_script_nodes.cpp | 1138 | ||||
-rw-r--r-- | modules/visual_script/visual_script_nodes.h | 216 | ||||
-rw-r--r-- | modules/visual_script/visual_script_yield_nodes.cpp | 622 | ||||
-rw-r--r-- | modules/visual_script/visual_script_yield_nodes.h | 127 |
15 files changed, 6659 insertions, 235 deletions
diff --git a/modules/visual_script/register_types.cpp b/modules/visual_script/register_types.cpp index da767c8447..1360e546f3 100644 --- a/modules/visual_script/register_types.cpp +++ b/modules/visual_script/register_types.cpp @@ -35,6 +35,7 @@ #include "visual_script_func_nodes.h" #include "visual_script_builtin_funcs.h" #include "visual_script_flow_control.h" +#include "visual_script_yield_nodes.h" VisualScriptLanguage *visual_script_language=NULL; @@ -44,9 +45,11 @@ void register_visual_script_types() { ObjectTypeDB::register_type<VisualScript>(); ObjectTypeDB::register_virtual_type<VisualScriptNode>(); + ObjectTypeDB::register_virtual_type<VisualScriptFunctionState>(); ObjectTypeDB::register_type<VisualScriptFunction>(); ObjectTypeDB::register_type<VisualScriptOperator>(); - ObjectTypeDB::register_type<VisualScriptVariable>(); + ObjectTypeDB::register_type<VisualScriptVariableSet>(); + ObjectTypeDB::register_type<VisualScriptVariableGet>(); ObjectTypeDB::register_type<VisualScriptConstant>(); ObjectTypeDB::register_type<VisualScriptIndexGet>(); ObjectTypeDB::register_type<VisualScriptIndexSet>(); @@ -56,6 +59,9 @@ void register_visual_script_types() { ObjectTypeDB::register_type<VisualScriptSceneNode>(); ObjectTypeDB::register_type<VisualScriptSceneTree>(); ObjectTypeDB::register_type<VisualScriptResourcePath>(); + ObjectTypeDB::register_type<VisualScriptSelf>(); + ObjectTypeDB::register_type<VisualScriptCustomNode>(); + ObjectTypeDB::register_type<VisualScriptSubCall>(); ObjectTypeDB::register_type<VisualScriptFunctionCall>(); ObjectTypeDB::register_type<VisualScriptPropertySet>(); @@ -68,6 +74,11 @@ void register_visual_script_types() { ObjectTypeDB::register_type<VisualScriptWhile>(); ObjectTypeDB::register_type<VisualScriptIterator>(); ObjectTypeDB::register_type<VisualScriptSequence>(); + ObjectTypeDB::register_type<VisualScriptInputFilter>(); + ObjectTypeDB::register_type<VisualScriptInputSelector>(); + + ObjectTypeDB::register_type<VisualScriptYield>(); + ObjectTypeDB::register_type<VisualScriptYieldSignal>(); ObjectTypeDB::register_type<VisualScriptBuiltinFunc>(); @@ -79,6 +90,7 @@ void register_visual_script_types() { register_visual_script_func_nodes(); register_visual_script_builtin_func_node(); register_visual_script_flow_control_nodes(); + register_visual_script_yield_nodes(); #ifdef TOOLS_ENABLED VisualScriptEditor::register_editor(); diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index 6f18bcfaee..425436d907 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -1,6 +1,20 @@ #include "visual_script.h" #include "visual_script_nodes.h" +#include "scene/main/node.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) { @@ -95,20 +109,44 @@ Ref<VisualScript> VisualScriptNode::get_visual_script() const { } +VisualScriptNode::VisualScriptNode() { + breakpoint=false; +} + //////////////// ///////////////////// +VisualScriptNodeInstance::VisualScriptNodeInstance() { + + sequence_outputs=NULL; + input_ports=NULL; +} + VisualScriptNodeInstance::~VisualScriptNodeInstance() { + if (sequence_outputs) { + memdelete(sequence_outputs); + } + + if (input_ports) { + memdelete(input_ports); + } + + if (output_ports) { + memdelete(output_ports); + } + } void VisualScript::add_function(const StringName& p_name) { + ERR_FAIL_COND( instances.size() ); ERR_FAIL_COND(!String(p_name).is_valid_identifier()); 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 { @@ -118,6 +156,7 @@ bool VisualScript::has_function(const StringName& p_name) const { } void VisualScript::remove_function(const StringName& p_name) { + ERR_FAIL_COND( instances.size() ); ERR_FAIL_COND(!functions.has(p_name)); for (Map<int,Function::NodeData>::Element *E=functions[p_name].nodes.front();E;E=E->next()) { @@ -132,6 +171,7 @@ void VisualScript::remove_function(const StringName& p_name) { void VisualScript::rename_function(const StringName& p_name,const StringName& p_new_name) { + ERR_FAIL_COND( instances.size() ); ERR_FAIL_COND(!functions.has(p_name)); if (p_new_name==p_name) return; @@ -147,6 +187,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()) { @@ -226,11 +281,14 @@ void VisualScript::_node_ports_changed(int p_id) { } } + set_edited(true); //something changed, let's set as edited emit_signal("node_ports_changed",function,p_id); + } void VisualScript::add_node(const StringName& p_func,int p_id, const Ref<VisualScriptNode>& p_node, const Point2 &p_pos) { + ERR_FAIL_COND( instances.size() ); ERR_FAIL_COND(!functions.has(p_func)); @@ -265,6 +323,7 @@ void VisualScript::add_node(const StringName& p_func,int p_id, const Ref<VisualS void VisualScript::remove_node(const StringName& p_func,int p_id){ + ERR_FAIL_COND( instances.size() ); ERR_FAIL_COND(!functions.has(p_func)); Function &func = functions[p_func]; @@ -314,6 +373,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{ @@ -327,6 +393,7 @@ Ref<VisualScriptNode> VisualScript::get_node(const StringName& p_func,int p_id) void VisualScript::set_node_pos(const StringName& p_func,int p_id,const Point2& p_pos) { + ERR_FAIL_COND( instances.size() ); ERR_FAIL_COND(!functions.has(p_func)); Function &func = functions[p_func]; @@ -358,6 +425,7 @@ void VisualScript::get_node_list(const StringName& p_func,List<int> *r_nodes) co void VisualScript::sequence_connect(const StringName& p_func,int p_from_node,int p_from_output,int p_to_node){ + ERR_FAIL_COND( instances.size() ); ERR_FAIL_COND(!functions.has(p_func)); Function &func = functions[p_func]; @@ -413,6 +481,7 @@ void VisualScript::get_sequence_connection_list(const StringName& p_func,List<Se void VisualScript::data_connect(const StringName& p_func,int p_from_node,int p_from_port,int p_to_node,int p_to_port) { + ERR_FAIL_COND( instances.size() ); ERR_FAIL_COND(!functions.has(p_func)); Function &func = functions[p_func]; @@ -484,6 +553,7 @@ void VisualScript::get_data_connection_list(const StringName& p_func,List<DataCo void VisualScript::add_variable(const StringName& p_name,const Variant& p_default_value) { + ERR_FAIL_COND( instances.size() ); ERR_FAIL_COND(!String(p_name).is_valid_identifier()); ERR_FAIL_COND(variables.has(p_name)); @@ -494,6 +564,12 @@ void VisualScript::add_variable(const StringName& p_name,const Variant& p_defaul v.info.hint=PROPERTY_HINT_NONE; variables[p_name]=v; + script_variable_remap[SCRIPT_VARIABLES_PREFIX+String(p_name)]=p_name; + + +#ifdef TOOLS_ENABLED + _update_placeholders(); +#endif } @@ -506,6 +582,11 @@ void VisualScript::remove_variable(const StringName& p_name) { ERR_FAIL_COND(!variables.has(p_name)); variables.erase(p_name); + script_variable_remap.erase(SCRIPT_VARIABLES_PREFIX+String(p_name)); + +#ifdef TOOLS_ENABLED + _update_placeholders(); +#endif } void VisualScript::set_variable_default_value(const StringName& p_name,const Variant& p_value){ @@ -514,6 +595,10 @@ void VisualScript::set_variable_default_value(const StringName& p_name,const Var variables[p_name].default_value=p_value; +#ifdef TOOLS_ENABLED + _update_placeholders(); +#endif + } Variant VisualScript::get_variable_default_value(const StringName& p_name) const{ @@ -523,10 +608,15 @@ Variant VisualScript::get_variable_default_value(const StringName& p_name) const } void VisualScript::set_variable_info(const StringName& p_name,const PropertyInfo& p_info){ + ERR_FAIL_COND( instances.size() ); ERR_FAIL_COND(!variables.has(p_name)); variables[p_name].info=p_info; variables[p_name].info.name=p_name; +#ifdef TOOLS_ENABLED + _update_placeholders(); +#endif + } PropertyInfo VisualScript::get_variable_info(const StringName& p_name) const{ @@ -578,12 +668,14 @@ void VisualScript::get_variable_list(List<StringName> *r_variables){ void VisualScript::set_instance_base_type(const StringName& p_type) { + ERR_FAIL_COND( instances.size() ); base_type=p_type; } void VisualScript::rename_variable(const StringName& p_name,const StringName& p_new_name) { + ERR_FAIL_COND( instances.size() ); ERR_FAIL_COND(!variables.has(p_name)); if (p_new_name==p_name) return; @@ -601,6 +693,7 @@ void VisualScript::rename_variable(const StringName& p_name,const StringName& p_ void VisualScript::add_custom_signal(const StringName& p_name) { + ERR_FAIL_COND( instances.size() ); ERR_FAIL_COND(!String(p_name).is_valid_identifier()); ERR_FAIL_COND(custom_signals.has(p_name)); @@ -614,6 +707,7 @@ bool VisualScript::has_custom_signal(const StringName& p_name) const { } void VisualScript::custom_signal_add_argument(const StringName& p_func,Variant::Type p_type,const String& p_name,int p_index) { + ERR_FAIL_COND( instances.size() ); ERR_FAIL_COND(!custom_signals.has(p_func)); Argument arg; arg.type=p_type; @@ -626,6 +720,7 @@ void VisualScript::custom_signal_add_argument(const StringName& p_func,Variant:: } void VisualScript::custom_signal_set_argument_type(const StringName& p_func,int p_argidx,Variant::Type p_type) { + ERR_FAIL_COND( instances.size() ); ERR_FAIL_COND(!custom_signals.has(p_func)); ERR_FAIL_INDEX(p_argidx,custom_signals[p_func].size()); custom_signals[p_func][p_argidx].type=p_type; @@ -637,6 +732,7 @@ Variant::Type VisualScript::custom_signal_get_argument_type(const StringName& p_ return custom_signals[p_func][p_argidx].type; } void VisualScript::custom_signal_set_argument_name(const StringName& p_func,int p_argidx,const String& p_name) { + ERR_FAIL_COND( instances.size() ); ERR_FAIL_COND(!custom_signals.has(p_func)); ERR_FAIL_INDEX(p_argidx,custom_signals[p_func].size()); custom_signals[p_func][p_argidx].name=p_name; @@ -651,6 +747,7 @@ String VisualScript::custom_signal_get_argument_name(const StringName& p_func,in } void VisualScript::custom_signal_remove_argument(const StringName& p_func,int p_argidx) { + ERR_FAIL_COND( instances.size() ); ERR_FAIL_COND(!custom_signals.has(p_func)); ERR_FAIL_INDEX(p_argidx,custom_signals[p_func].size()); custom_signals[p_func].remove(p_argidx); @@ -665,6 +762,7 @@ int VisualScript::custom_signal_get_argument_count(const StringName& p_func) con } void VisualScript::custom_signal_swap_argument(const StringName& p_func,int p_argidx,int p_with_argidx) { + ERR_FAIL_COND( instances.size() ); ERR_FAIL_COND(!custom_signals.has(p_func)); ERR_FAIL_INDEX(p_argidx,custom_signals[p_func].size()); ERR_FAIL_INDEX(p_with_argidx,custom_signals[p_func].size()); @@ -674,6 +772,7 @@ void VisualScript::custom_signal_swap_argument(const StringName& p_func,int p_ar } void VisualScript::remove_custom_signal(const StringName& p_name) { + ERR_FAIL_COND( instances.size() ); ERR_FAIL_COND(!custom_signals.has(p_name)); custom_signals.erase(p_name); @@ -681,6 +780,7 @@ void VisualScript::remove_custom_signal(const StringName& p_name) { void VisualScript::rename_custom_signal(const StringName& p_name,const StringName& p_new_name) { + ERR_FAIL_COND( instances.size() ); ERR_FAIL_COND(!custom_signals.has(p_name)); if (p_new_name==p_name) return; @@ -725,7 +825,7 @@ int VisualScript::get_available_id() const { bool VisualScript::can_instance() const { - return ScriptServer::is_scripting_enabled(); + return true;//ScriptServer::is_scripting_enabled(); } @@ -735,14 +835,88 @@ StringName VisualScript::get_instance_base_type() const { return base_type; } + +#ifdef TOOLS_ENABLED +void VisualScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) { + + + placeholders.erase(p_placeholder); +} + + +void VisualScript::_update_placeholders() { + + if (placeholders.size()==0) + return; //no bother if no placeholders + List<PropertyInfo> pinfo; + Map<StringName,Variant> values; + + for (Map<StringName,Variable>::Element *E=variables.front();E;E=E->next()) { + + PropertyInfo p = E->get().info; + p.name=SCRIPT_VARIABLES_PREFIX+String(E->key()); + pinfo.push_back(p); + values[p.name]=E->get().default_value; + } + + for (Set<PlaceHolderScriptInstance*>::Element *E=placeholders.front();E;E=E->next()) { + + E->get()->update(pinfo,values); + } + +} + +#endif + + ScriptInstance* VisualScript::instance_create(Object *p_this) { - return NULL; + + +#ifdef TOOLS_ENABLED + + if (!ScriptServer::is_scripting_enabled()) { + + + PlaceHolderScriptInstance *sins = memnew( PlaceHolderScriptInstance(VisualScriptLanguage::singleton,Ref<Script>((Script*)this),p_this)); + placeholders.insert(sins); + + List<PropertyInfo> pinfo; + Map<StringName,Variant> values; + + for (Map<StringName,Variable>::Element *E=variables.front();E;E=E->next()) { + + PropertyInfo p = E->get().info; + p.name=SCRIPT_VARIABLES_PREFIX+String(E->key()); + pinfo.push_back(p); + values[p.name]=E->get().default_value; + } + + sins->update(pinfo,values); + + return sins; + } +#endif + + + VisualScriptInstance *instance=memnew( VisualScriptInstance ); + instance->create(Ref<VisualScript>(this),p_this); + + + if (VisualScriptLanguage::singleton->lock) + VisualScriptLanguage::singleton->lock->lock(); + + instances[p_this]=instance; + + if (VisualScriptLanguage::singleton->lock) + VisualScriptLanguage::singleton->lock->unlock(); + + return instance; } bool VisualScript::instance_has(const Object *p_this) const { - return false; + return instances.has((Object*)p_this); } bool VisualScript::has_source_code() const { @@ -785,17 +959,37 @@ ScriptLanguage *VisualScript::get_language() const { bool VisualScript::has_script_signal(const StringName& p_signal) const { - return false; + return custom_signals.has(p_signal); } void VisualScript::get_script_signal_list(List<MethodInfo> *r_signals) const { + for (const Map<StringName,Vector<Argument> >::Element *E=custom_signals.front();E;E=E->next()) { + + MethodInfo mi; + mi.name=E->key(); + for(int i=0;i<E->get().size();i++) { + PropertyInfo arg; + arg.type=E->get()[i].type; + arg.name=E->get()[i].name; + mi.arguments.push_back(arg); + } + + + r_signals->push_back(mi); + } + + } bool VisualScript::get_property_default_value(const StringName& p_property,Variant& r_value) const { - return false; + if (!script_variable_remap.has(p_property)) + return false; + + r_value=variables[ script_variable_remap[p_property] ].default_value; + return true; } void VisualScript::get_method_list(List<MethodInfo> *p_list) const { @@ -821,6 +1015,36 @@ void VisualScript::get_method_list(List<MethodInfo> *p_list) const { } } +bool VisualScript::has_method(const StringName& p_method) const { + + return functions.has(p_method); +} +MethodInfo VisualScript::get_method_info(const StringName& p_method) const{ + + const Map<StringName,Function>::Element *E=functions.find(p_method); + if (!E) + return MethodInfo(); + + MethodInfo mi; + mi.name=E->key(); + if (E->get().function_id>=0) { + + Ref<VisualScriptFunction> func=E->get().nodes[E->get().function_id].node; + if (func.is_valid()) { + + for(int i=0;i<func->get_argument_count();i++) { + PropertyInfo arg; + arg.name=func->get_argument_name(i); + arg.type=func->get_argument_type(i); + mi.arguments.push_back(arg); + } + } + } + + return mi; +} + + void VisualScript::_set_data(const Dictionary& p_data) { Dictionary d = p_data; @@ -832,8 +1056,11 @@ void VisualScript::_set_data(const Dictionary& p_data) { for (int i=0;i<vars.size();i++) { Dictionary v=vars[i]; - add_variable(v["name"],v["default_value"]); - _set_variable_info(v["name"],v); + StringName name = v["name"]; + add_variable(name); + _set_variable_info(name,v); + set_variable_default_value(name,v["default_value"]); + } @@ -857,10 +1084,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) { @@ -928,6 +1158,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; @@ -989,12 +1220,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); @@ -1058,6 +1292,948 @@ VisualScript::~VisualScript() { //////////////////////////////////////////// + +bool VisualScriptInstance::set(const StringName& p_name, const Variant& p_value) { + + const Map<StringName,StringName>::Element *remap = script->script_variable_remap.find(p_name); + if (!remap) + return false; + + Map<StringName,Variant>::Element *E=variables.find(remap->get()); + ERR_FAIL_COND_V(!E,false); + + E->get()=p_value; + + return true; +} + + +bool VisualScriptInstance::get(const StringName& p_name, Variant &r_ret) const { + + const Map<StringName,StringName>::Element *remap = script->script_variable_remap.find(p_name); + if (!remap) + return false; + + const Map<StringName,Variant>::Element *E=variables.find(remap->get()); + ERR_FAIL_COND_V(!E,false); + + return E->get(); +} +void VisualScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const{ + + for (const Map<StringName,VisualScript::Variable>::Element *E=script->variables.front();E;E=E->next()) { + + PropertyInfo p = E->get().info; + p.name=SCRIPT_VARIABLES_PREFIX+String(E->key()); + p_properties->push_back(p); + + } +} +Variant::Type VisualScriptInstance::get_property_type(const StringName& p_name,bool *r_is_valid) const{ + + const Map<StringName,StringName>::Element *remap = script->script_variable_remap.find(p_name); + if (!remap) { + if (r_is_valid) + *r_is_valid=false; + return Variant::NIL; + } + + const Map<StringName,VisualScript::Variable>::Element *E=script->variables.find(remap->get()); + if (!E) { + if (r_is_valid) + *r_is_valid=false; + ERR_FAIL_V(Variant::NIL); + } + + if (r_is_valid) + *r_is_valid=true; + + return E->get().info.type; + +} + +void VisualScriptInstance::get_method_list(List<MethodInfo> *p_list) const{ + + for (const Map<StringName,VisualScript::Function>::Element *E=script->functions.front();E;E=E->next()) { + + MethodInfo mi; + mi.name=E->key(); + 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()) { + + for(int i=0;i<vsf->get_argument_count();i++) { + PropertyInfo arg; + arg.name=vsf->get_argument_name(i); + arg.type=vsf->get_argument_type(i); + + mi.arguments.push_back(arg); + } + + //vsf->Get_ for now at least it does not return.. + } + } + + p_list->push_back(mi); + } + +} +bool VisualScriptInstance::has_method(const StringName& p_method) const{ + + return script->functions.has(p_method); +} + + +//#define VSDEBUG(m_text) print_line(m_text) +#define VSDEBUG(m_text) + +Variant VisualScriptInstance::_call_internal(const StringName& p_method, void* p_stack, int p_stack_size, VisualScriptNodeInstance* p_node, int p_flow_stack_pos, bool p_resuming_yield, Variant::CallError &r_error) { + + Map<StringName,Function>::Element *F = functions.find(p_method); + ERR_FAIL_COND_V(!F,Variant()); + Function *f=&F->get(); + + //this call goes separate, so it can e yielded and suspended + Variant *variant_stack=(Variant*)p_stack; + bool *sequence_bits = (bool*)(variant_stack + f->max_stack); + const Variant **input_args=(const Variant**)(sequence_bits+f->node_count); + Variant **output_args=(Variant**)(input_args + max_input_args); + int flow_max = f->flow_stack_size; + int* flow_stack = flow_max? (int*)(output_args + max_output_args) : (int*)NULL; + + String error_str; + + VisualScriptNodeInstance* node=p_node; + bool error=false; + int current_node_id=f->node; + Variant return_value; + Variant *working_mem=NULL; + + int flow_stack_pos=p_flow_stack_pos; + +#ifdef DEBUG_ENABLED + if (ScriptDebugger::get_singleton()) { + VisualScriptLanguage::singleton->enter_function(this,&p_method,variant_stack,&working_mem,¤t_node_id); + } +#endif + + while(true) { + + current_node_id=node->get_id(); + + VSDEBUG("==========AT NODE: "+itos(current_node_id)+" base: "+node->get_base_node()->get_type()); + VSDEBUG("AT STACK POS: "+itos(flow_stack_pos)); + + + //setup working mem + working_mem=node->working_mem_idx>=0 ? &variant_stack[node->working_mem_idx] : (Variant*)NULL; + + VSDEBUG("WORKING MEM: "+itos(node->working_mem_idx)); + + if (current_node_id==f->node) { + //if function node, set up function arguments from begining of stack + + for(int i=0;i<f->argument_count;i++) { + input_args[i]=&variant_stack[i]; + } + } else { + //setup input pointers normally + VSDEBUG("INPUT PORTS: "+itos(node->input_port_count)); + + for(int i=0 ; i<node->input_port_count ; i++) { + + + int index = node->input_ports[i] & VisualScriptNodeInstance::INPUT_MASK; + + if (node->input_ports[i] & VisualScriptNodeInstance::INPUT_DEFAULT_VALUE_BIT) { + //is a default value (unassigned input port) + input_args[i]=&default_values[index]; + VSDEBUG("\tPORT "+itos(i)+" DEFAULT VAL"); + } else if (node->input_ports[i] & VisualScriptNodeInstance::INPUT_UNSEQUENCED_READ_BIT) { + //from a node that requires read + Function::UnsequencedGet *ug = &f->unsequenced_gets[index]; + + bool ok = ug->from->get_output_port_unsequenced(i,&variant_stack[ug->to_stack],working_mem,error_str); + if (!ok) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + current_node_id=ug->from->get_id(); + error=true; + working_mem=NULL; + break; + } + + VSDEBUG("\tPORT "+itos(i)+" UNSEQ READ TO STACK: " + itos(ug->to_stack)); + input_args[i]=&variant_stack[ug->to_stack]; + } else { + //regular temporary in stack + input_args[i]=&variant_stack[index]; + VSDEBUG("PORT "+itos(i)+" AT STACK "+itos(index)); + + } + } + } + + if (error) + break; + + //setup output pointers + + VSDEBUG("OUTPUT PORTS: "+itos(node->output_port_count)); + for(int i=0 ; i<node->output_port_count ; i++) { + output_args[i] = &variant_stack[ node->output_ports[i] ]; + VSDEBUG("PORT "+itos(i)+" AT STACK "+itos(node->output_ports[i])); + } + + //do step + + VisualScriptNodeInstance::StartMode start_mode; + { + if (p_resuming_yield) + start_mode=VisualScriptNodeInstance::START_MODE_RESUME_YIELD; + else if (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 + start_mode=VisualScriptNodeInstance::START_MODE_BEGIN_SEQUENCE; + else + start_mode=VisualScriptNodeInstance::START_MODE_CONTINUE_SEQUENCE; + } + + VSDEBUG("STEP - STARTSEQ: "+itos(start_sequence)); + + int ret = node->step(input_args,output_args,start_mode,working_mem,r_error,error_str); + + if (r_error.error!=Variant::CallError::CALL_OK) { + //use error from step + error=true; + break; + } + + if (ret&VisualScriptNodeInstance::STEP_YIELD_BIT) { + //yielded! + if (node->get_working_memory_size()==0) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + error_str=RTR("A node yielded without working memory, please read the docs on how to yield properly!"); + error=true; + break; + + } else { + Ref<VisualScriptFunctionState> state = *working_mem; + if (!state.is_valid()) { + + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + error_str=RTR("Node yielded, but did not return a function state in the first working memory."); + error=true; + break; + + } + + //step 1, capture all state + state->instance_id=get_owner_ptr()->get_instance_ID(); + state->script_id=get_script()->get_instance_ID(); + state->instance=this; + state->function=p_method; + state->working_mem_index=node->working_mem_idx; + state->variant_stack_size=f->max_stack; + state->node=node; + state->flow_stack_pos=flow_stack_pos; + state->stack.resize(p_stack_size); + copymem(state->stack.ptr(),p_stack,p_stack_size); + //step 2, run away, return directly + r_error.error=Variant::CallError::CALL_OK; + + +#ifdef DEBUG_ENABLED + //will re-enter later, so exiting + if (ScriptDebugger::get_singleton()) { + VisualScriptLanguage::singleton->exit_function(); + } +#endif + + return state; + + } + } + +#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)); + + if (ret & VisualScriptNodeInstance::STEP_EXIT_FUNCTION_BIT) { + if (node->get_working_memory_size()==0) { + + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + error_str=RTR("Return value must be assigned to first element of node working memory! Fix your node please."); + error=true; + } else { + //assign from working memory, first element + return_value=*working_mem; + } + + VSDEBUG("EXITING FUNCTION - VALUE "+String(return_value)); + break; //exit function requested, bye + } + + VisualScriptNodeInstance *next=NULL; //next node + + if ( (ret==output || ret&VisualScriptNodeInstance::STEP_FLAG_PUSH_STACK_BIT) && node->sequence_output_count) { + //if no exit bit was set, and has sequence outputs, guess next node + if (output<0 || output>=node->sequence_output_count) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + error_str=RTR("Node returned an invalid sequence output: ")+itos(output); + error=true; + break; + } + + next = node->sequence_outputs[output]; + if (next) { + VSDEBUG("GOT NEXT NODE - "+itos(next->get_id())); + } else { + VSDEBUG("GOT NEXT NODE - NULL"); + } + } + + if (flow_stack) { + + //update flow stack pos (may have changed) + flow_stack[flow_stack_pos] = current_node_id; + + //add stack push bit if requested + if (ret & VisualScriptNodeInstance::STEP_FLAG_PUSH_STACK_BIT) { + + flow_stack[flow_stack_pos] |= VisualScriptNodeInstance::FLOW_STACK_PUSHED_BIT; + sequence_bits[ node ->sequence_index ]=true; //remember sequence bit + VSDEBUG("NEXT SEQ - FLAG BIT"); + } else { + sequence_bits[ node ->sequence_index ]=false; //forget sequence bit + VSDEBUG("NEXT SEQ - NORMAL"); + } + + + if (ret & VisualScriptNodeInstance::STEP_FLAG_GO_BACK_BIT) { + //go back request + + if (flow_stack_pos>0) { + flow_stack_pos--; + node = instances[ flow_stack[flow_stack_pos] & VisualScriptNodeInstance::FLOW_STACK_MASK ]; + VSDEBUG("NEXT IS GO BACK"); + } else { + VSDEBUG("NEXT IS GO BACK, BUT NO NEXT SO EXIT"); + break; //simply exit without value or error + } + } else if (next) { + + + if (sequence_bits[next->sequence_index]) { + // what happened here is that we are entering a node that is in the middle of doing a sequence (pushed stack) from the front + // because each node has a working memory, we can't really do a sub-sequence + // as a result, the sequence will be restarted and the stack will roll back to find where this node + // started the sequence + + bool found = false; + + for(int i=flow_stack_pos;i>=0;i--) { + + + if ( (flow_stack[i] & VisualScriptNodeInstance::FLOW_STACK_MASK ) == next->get_id() ) { + flow_stack_pos=i; //roll back and remove bit + flow_stack[i]=next->get_id(); + sequence_bits[next->sequence_index]=false; + found=true; + } + } + + if (!found) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + error_str=RTR("Found sequence bit but not the node in the stack, report bug!"); + error=true; + break; + } + + node=next; + VSDEBUG("RE-ENTERED A LOOP, RETURNED STACK POS TO - "+itos(flow_stack_pos)); + + } else { + // check for stack overflow + if (flow_stack_pos+1 >= flow_max) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + error_str=RTR("Stack overflow with stack depth: ")+itos(output); + error=true; + break; + } + + node = next; + + flow_stack_pos++; + flow_stack[flow_stack_pos]=node->get_id(); + + VSDEBUG("INCREASE FLOW STACK"); + + } + + } else { + //no next node, try to go back in stack to pushed bit + + bool found = false; + + for(int i=flow_stack_pos;i>=0;i--) { + + VSDEBUG("FS "+itos(i)+" - "+itos(flow_stack[i])); + if (flow_stack[i] & VisualScriptNodeInstance::FLOW_STACK_PUSHED_BIT) { + + node = instances[ flow_stack[i] & VisualScriptNodeInstance::FLOW_STACK_MASK ]; + flow_stack_pos=i; + found=true; + } + } + + if (!found) { + VSDEBUG("NO NEXT NODE, NO GO BACK, EXITING"); + break; //done, couldn't find a push stack bit + } + + VSDEBUG("NO NEXT NODE, GO BACK TO: "+itos(flow_stack_pos)); + + } + } else { + + node=next; //stackless mode, simply assign next node + } + + } + + + + if (error) { + + //error + // function, file, line, error, explanation + String err_file = script->get_path(); + String err_func = p_method; + int err_line=current_node_id; //not a line but it works as one + + + //if (!GDScriptLanguage::get_singleton()->debug_break(err_text,false)) { + // debugger break did not happen + + 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 { + + + //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++) { + variant_stack[i].~Variant(); + } + + + return return_value; +} + + +Variant VisualScriptInstance::call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error){ + + r_error.error=Variant::CallError::CALL_OK; //ok by default + + Map<StringName,Function>::Element *F = functions.find(p_method); + if (!F) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + return Variant(); + } + + VSDEBUG("CALLING: "+String(p_method)); + + Function *f=&F->get(); + + int total_stack_size=0; + + total_stack_size+=f->max_stack*sizeof(Variant); //variants + total_stack_size+=f->node_count*sizeof(bool); + total_stack_size+=(max_input_args+max_output_args)*sizeof(Variant*); //arguments + total_stack_size+=f->flow_stack_size*sizeof(int); //flow + + VSDEBUG("STACK SIZE: "+itos(total_stack_size)); + VSDEBUG("STACK VARIANTS: : "+itos(f->max_stack)); + VSDEBUG("SEQBITS: : "+itos(f->node_count)); + VSDEBUG("MAX INPUT: "+itos(max_input_args)); + VSDEBUG("MAX OUTPUT: "+itos(max_output_args)); + VSDEBUG("FLOW STACK SIZE: "+itos(f->flow_stack_size)); + + void *stack = alloca(total_stack_size); + + Variant *variant_stack=(Variant*)stack; + bool *sequence_bits = (bool*)(variant_stack + f->max_stack); + const Variant **input_args=(const Variant**)(sequence_bits+f->node_count); + Variant **output_args=(Variant**)(input_args + max_input_args); + int flow_max = f->flow_stack_size; + int* flow_stack = flow_max? (int*)(output_args + max_output_args) : (int*)NULL; + + for(int i=0;i<f->node_count;i++) { + sequence_bits[i]=false; //all starts as false + } + + + Map<int,VisualScriptNodeInstance*>::Element *E = instances.find(f->node); + if (!E) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + + ERR_EXPLAIN("No VisualScriptFunction node in function!"); + ERR_FAIL_V(Variant()); + } + + VisualScriptNodeInstance *node = E->get(); + + + if (flow_stack) { + flow_stack[0]=node->get_id(); + } + + VSDEBUG("ARGUMENTS: "+itos(f->argument_count)=" RECEIVED: "+itos(p_argcount)); + + if (p_argcount<f->argument_count) { + r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.argument=node->get_input_port_count(); + + return Variant(); + } + + if (p_argcount>f->argument_count) { + r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; + r_error.argument=node->get_input_port_count(); + + return Variant(); + } + + //allocate variant stack + for(int i=0;i<f->max_stack;i++) { + memnew_placement(&variant_stack[i],Variant); + } + + //allocate function arguments (must be copied for yield to work properly) + for(int i=0;i<p_argcount;i++) { + variant_stack[i]=*p_args[i]; + } + + return _call_internal(p_method,stack,total_stack_size,node,0,false,r_error); + + +} + +void VisualScriptInstance::notification(int p_notification){ + + //do nothing as this is called using virtual + + Variant what=p_notification; + const Variant*whatp=&what; + Variant::CallError ce; + call(VisualScriptLanguage::singleton->notification,&whatp,1,ce); //do as call + +} + +Ref<Script> VisualScriptInstance::get_script() const{ + + return script; +} + + +void VisualScriptInstance::create(const Ref<VisualScript>& p_script,Object *p_owner) { + + script=p_script; + owner=p_owner; + source=p_script->get_path(); + + max_input_args = 0; + max_output_args = 0; + + if (p_owner->cast_to<Node>()) { + //turn on these if they exist and base is a node + Node* node = p_owner->cast_to<Node>(); + if (p_script->functions.has("_process")) + node->set_process(true); + if (p_script->functions.has("_fixed_process")) + node->set_fixed_process(true); + if (p_script->functions.has("_input")) + node->set_process_input(true); + if (p_script->functions.has("_unhandled_input")) + node->set_process_unhandled_input(true); + if (p_script->functions.has("_unhandled_key_input")) + node->set_process_unhandled_key_input(true); + } + + for(const Map<StringName,VisualScript::Variable>::Element *E=script->variables.front();E;E=E->next()) { + variables[E->key()]=E->get().default_value; + } + + + for(const Map<StringName,VisualScript::Function>::Element *E=script->functions.front();E;E=E->next()) { + + Function function; + function.node=E->get().function_id; + function.max_stack=0; + function.flow_stack_size=0; + function.node_count=0; + + if (function.node<0) { + VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(),0,"No start node in function: "+String(E->key())); + + ERR_CONTINUE( function.node < 0 ); + } + + { + Ref<VisualScriptFunction> func_node = script->get_node(E->key(),E->get().function_id); + + 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(); + function.max_stack+=function.argument_count; + function.flow_stack_size= func_node->is_stack_less() ? 0 : func_node->get_stack_size(); + + } + + //multiple passes are required to set up this complex thing.. + + + + + //first create the nodes + for (const Map<int,VisualScript::Function::NodeData>::Element *F=E->get().nodes.front();F;F=F->next()) { + + Ref<VisualScriptNode> node = F->get().node; + VisualScriptNodeInstance *instance = node->instance(this); //create instance + ERR_FAIL_COND(!instance); + + instance->base=node.ptr(); + + instance->id=F->key(); + instance->input_port_count = node->get_input_value_port_count(); + instance->output_port_count = node->get_output_value_port_count(); + instance->sequence_output_count = node->get_output_sequence_port_count(); + instance->sequence_index=function.node_count++; + + if (instance->input_port_count) { + instance->input_ports = memnew_arr(int,instance->input_port_count); + for(int i=0;i<instance->input_port_count;i++) { + instance->input_ports[i]=-1; //if not assigned, will become default value + } + } + + if (instance->output_port_count) { + instance->output_ports = memnew_arr(int,instance->output_port_count); + for(int i=0;i<instance->output_port_count;i++) { + instance->output_ports[i]=-1; //if not assigned, will output to trash + } + } + + if (instance->sequence_output_count) { + instance->sequence_outputs = memnew_arr(VisualScriptNodeInstance*,instance->sequence_output_count); + for(int i=0;i<instance->sequence_output_count;i++) { + instance->sequence_outputs[i]=NULL; //if it remains null, flow ends here + } + } + + if (instance->get_working_memory_size()) { + instance->working_mem_idx = function.max_stack; + function.max_stack+=instance->get_working_memory_size(); + } else { + instance->working_mem_idx=-1; //no working mem + } + + max_input_args = MAX( max_input_args, instance->input_port_count ); + max_output_args = MAX( max_output_args, instance->output_port_count ); + + instances[F->key()]=instance; + + + } + + function.trash_pos = function.max_stack++; //create pos for trash + + //second pass, do data connections + + for(const Set<VisualScript::DataConnection>::Element *F=E->get().data_connections.front();F;F=F->next()) { + + VisualScript::DataConnection dc = F->get(); + ERR_CONTINUE(!instances.has(dc.from_node)); + VisualScriptNodeInstance *from = instances[dc.from_node]; + ERR_CONTINUE(!instances.has(dc.to_node)); + VisualScriptNodeInstance *to = instances[dc.to_node]; + ERR_CONTINUE(dc.from_port >= from->output_port_count); + ERR_CONTINUE(dc.to_port >= to->input_port_count); + + if (from->output_ports[dc.from_port]==-1) { + + int stack_pos = function.max_stack++; + from->output_ports[dc.from_port] = stack_pos; + } + + + if (from->is_output_port_unsequenced(dc.from_node)) { + + //prepare an unsequenced read (must actually get the value from the output) + int stack_pos = function.max_stack++; + + Function::UnsequencedGet uget; + uget.from=from; + uget.from_port=dc.from_port; + uget.to_stack=stack_pos; + + to->input_ports[dc.to_port] = function.unsequenced_gets.size() | VisualScriptNodeInstance::INPUT_UNSEQUENCED_READ_BIT; + function.unsequenced_gets.push_back(uget); + + } else { + + to->input_ports[dc.to_port] = from->output_ports[dc.from_port]; //read from wherever the stack is + } + + } + + //third pass, do sequence connections + + for(const Set<VisualScript::SequenceConnection>::Element *F=E->get().sequence_connections.front();F;F=F->next()) { + + VisualScript::SequenceConnection sc = F->get(); + ERR_CONTINUE(!instances.has(sc.from_node)); + VisualScriptNodeInstance *from = instances[sc.from_node]; + ERR_CONTINUE(!instances.has(sc.to_node)); + VisualScriptNodeInstance *to = instances[sc.to_node]; + ERR_CONTINUE(sc.from_output >= from->sequence_output_count); + + from->sequence_outputs[sc.from_output]=to; + + } + + //fourth pass: + // 1) unassigned input ports to default values + // 2) connect unassigned output ports to trash + + + for (const Map<int,VisualScript::Function::NodeData>::Element *F=E->get().nodes.front();F;F=F->next()) { + + ERR_CONTINUE(!instances.has(F->key())); + + Ref<VisualScriptNode> node = F->get().node; + VisualScriptNodeInstance *instance = instances[F->key()]; + + // conect to default values + for(int i=0;i<instance->input_port_count;i++) { + if (instance->input_ports[i]==-1) { + + //unassigned, connect to default val + instance->input_ports[i] = default_values.size() | VisualScriptNodeInstance::INPUT_DEFAULT_VALUE_BIT; + default_values.push_back( node->get_default_input_value(i) ); + } + } + + // conect to trash + for(int i=0;i<instance->output_port_count;i++) { + if (instance->output_ports[i]==-1) { + instance->output_ports[i] = function.trash_pos; //trash is same for all + } + } + } + + + functions[E->key()]=function; + } +} + +ScriptLanguage *VisualScriptInstance::get_language(){ + + return VisualScriptLanguage::singleton; +} + + +VisualScriptInstance::VisualScriptInstance() { + + +} + +VisualScriptInstance::~VisualScriptInstance() { + + if (VisualScriptLanguage::singleton->lock) + VisualScriptLanguage::singleton->lock->lock(); + + script->instances.erase(owner); + + if (VisualScriptLanguage::singleton->lock) + VisualScriptLanguage::singleton->lock->unlock(); + + for (Map<int,VisualScriptNodeInstance*>::Element *E=instances.front();E;E=E->next()) { + memdelete(E->get()); + } +} + + + +///////////////////////////////////////////// + + +///////////////////// + + +Variant VisualScriptFunctionState::_signal_callback(const Variant** p_args, int p_argcount, Variant::CallError& r_error) { + + ERR_FAIL_COND_V(function==StringName(),Variant()); + +#ifdef DEBUG_ENABLED + if (instance_id && !ObjectDB::get_instance(instance_id)) { + ERR_EXPLAIN("Resumed after yield, but class instance is gone"); + ERR_FAIL_V(Variant()); + } + + if (script_id && !ObjectDB::get_instance(script_id)) { + ERR_EXPLAIN("Resumed after yield, but script is gone"); + ERR_FAIL_V(Variant()); + } +#endif + + r_error.error=Variant::CallError::CALL_OK; + + Array args; + + if (p_argcount==0) { + r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.argument=1; + return Variant(); + } else if (p_argcount==1) { + //noooneee, reserved for me, me and only me. + } else { + + for(int i=0;i<p_argcount-1;i++) { + args.push_back(*p_args[i]); + } + } + + Ref<VisualScriptFunctionState> self = *p_args[p_argcount-1]; //hi, I'm myself, needed this to remain alive. + + if (self.is_null()) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=p_argcount-1; + r_error.expected=Variant::OBJECT; + return Variant(); + } + + r_error.error=Variant::CallError::CALL_OK; + + Variant *working_mem = ((Variant*)stack.ptr()) + working_mem_index; + + *working_mem=args; //arguments go to working mem. + + Variant ret = instance->_call_internal(function,stack.ptr(),stack.size(),node,flow_stack_pos,true,r_error); + function=StringName(); //invalidate + return ret; +} + +void VisualScriptFunctionState::connect_to_signal(Object* p_obj, const String& p_signal, Array p_binds) { + + Vector<Variant> binds; + for(int i=0;i<p_binds.size();i++) { + binds.push_back(p_binds[i]); + } + binds.push_back(Ref<VisualScriptFunctionState>(this)); //add myself on the back to avoid dying from unreferencing + p_obj->connect(p_signal,this,"_signal_callback",binds); +} + +bool VisualScriptFunctionState::is_valid() const { + + return function!=StringName(); +} + +Variant VisualScriptFunctionState::resume(Array p_args) { + + ERR_FAIL_COND_V(function==StringName(),Variant()); +#ifdef DEBUG_ENABLED + if (instance_id && !ObjectDB::get_instance(instance_id)) { + ERR_EXPLAIN("Resumed after yield, but class instance is gone"); + ERR_FAIL_V(Variant()); + } + + if (script_id && !ObjectDB::get_instance(script_id)) { + ERR_EXPLAIN("Resumed after yield, but script is gone"); + ERR_FAIL_V(Variant()); + } +#endif + + Variant::CallError r_error; + r_error.error=Variant::CallError::CALL_OK; + + Variant *working_mem = ((Variant*)stack.ptr()) + working_mem_index; + + *working_mem=p_args; //arguments go to working mem. + + Variant ret= instance->_call_internal(function,stack.ptr(),stack.size(),node,flow_stack_pos,true,r_error); + function=StringName(); //invalidate + return ret; +} + + +void VisualScriptFunctionState::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("connect_to_signal","obj","signals","args"),&VisualScriptFunctionState::connect_to_signal); + ObjectTypeDB::bind_method(_MD("resume:Array","args"),&VisualScriptFunctionState::resume,DEFVAL(Variant())); + ObjectTypeDB::bind_method(_MD("is_valid"),&VisualScriptFunctionState::is_valid); + ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"_signal_callback",&VisualScriptFunctionState::_signal_callback,MethodInfo("_signal_callback")); +} + +VisualScriptFunctionState::VisualScriptFunctionState() { + +} + +VisualScriptFunctionState::~VisualScriptFunctionState() { + + if (function!=StringName()) { + Variant *s = ((Variant*)stack.ptr()); + for(int i=0;i<variant_stack_size;i++) { + s[i].~Variant(); + } + } +} + + + + + +/////////////////////////////////////////////// + String VisualScriptLanguage::get_name() const { return "VisualScript"; @@ -1098,9 +2274,12 @@ void VisualScriptLanguage::get_string_delimiters(List<String> *p_delimiters) con } -String VisualScriptLanguage::get_template(const String& p_class_name, const String& p_base_class_name) const { +Ref<Script> VisualScriptLanguage::get_template(const String& p_class_name, const String& p_base_class_name) const { - return String(); + Ref<VisualScript> script; + script.instance(); + script->set_instance_base_type(p_base_class_name); + return script; } bool VisualScriptLanguage::validate(const String& p_script, int &r_line_error,int &r_col_error,String& r_test_error, const String& p_path,List<String> *r_functions) const { @@ -1135,44 +2314,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() { @@ -1243,5 +2577,41 @@ void VisualScriptLanguage::get_registered_node_names(List<String> *r_names) { VisualScriptLanguage::VisualScriptLanguage() { + notification="_notification"; + _get_output_port_unsequenced="_get_output_port_unsequenced"; + _step="_step"; + _subcall="_subcall"; singleton=this; +#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 26daddbba6..786b9b873e 100644 --- a/modules/visual_script/visual_script.h +++ b/modules/visual_script/visual_script.h @@ -2,9 +2,9 @@ #define VSCRIPT_H #include "script_language.h" +#include "os/thread.h" - -class VScriptInstance; +class VisualScriptInstance; class VisualScriptNodeInstance; class VisualScript; @@ -16,11 +16,14 @@ 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; protected: + virtual bool _use_builtin_script() const { return false; } + void _notification(int p_what); void ports_changed_notify(); static void _bind_methods(); @@ -45,22 +48,82 @@ public: virtual String get_caption() const=0; 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(VScriptInstance* p_instance)=0; + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance)=0; + VisualScriptNode(); }; class VisualScriptNodeInstance { +friend class VisualScriptInstance; +friend class VisualScriptLanguage; //for debugger + + + enum { //input argument addressing + INPUT_SHIFT=1<<24, + INPUT_MASK=INPUT_SHIFT-1, + INPUT_DEFAULT_VALUE_BIT=INPUT_SHIFT, // from unassigned input port, using default value (edited by user) + INPUT_UNSEQUENCED_READ_BIT=INPUT_SHIFT<<1, //from unsequenced read (requires calling a function, used for constants, variales, etc). + }; + + + int id; + int sequence_index; + VisualScriptNodeInstance **sequence_outputs; + int sequence_output_count; + int *input_ports; + int input_port_count; + int *output_ports; + int output_port_count; + int working_mem_idx; + + VisualScriptNode *base; + public: - virtual int step()=0; //do a step, return which sequence port to go out + enum StartMode { + START_MODE_BEGIN_SEQUENCE, + START_MODE_CONTINUE_SEQUENCE, + START_MODE_RESUME_YIELD + }; + + enum { + STEP_SHIFT=1<<24, + STEP_MASK=STEP_SHIFT-1, + STEP_FLAG_PUSH_STACK_BIT=STEP_SHIFT, //push bit to stack + STEP_FLAG_GO_BACK_BIT=STEP_SHIFT<<1, //go back to previous node + STEP_NO_ADVANCE_BIT=STEP_SHIFT<<2, //do not advance past this node + STEP_EXIT_FUNCTION_BIT=STEP_SHIFT<<3, //return from function + STEP_YIELD_BIT=STEP_SHIFT<<4, //yield (will find VisualScriptFunctionState state in first working memory) + + FLOW_STACK_PUSHED_BIT=1<<30, //in flow stack, means bit was pushed (must go back here if end of sequence) + FLOW_STACK_MASK=FLOW_STACK_PUSHED_BIT-1 + + }; + + _FORCE_INLINE_ int get_input_port_count() const { return input_port_count; } + _FORCE_INLINE_ int get_output_port_count() const { return output_port_count; } + _FORCE_INLINE_ int get_sequence_output_count() const { return sequence_output_count; } + + _FORCE_INLINE_ int get_id() const { return id; } - virtual Variant get_input_value(int p_idx)=0; - virtual Variant get_output_value(int p_idx)=0; + virtual int get_working_memory_size() const { return 0; } - virtual VisualScriptNode* get_node()=0; + //unsequenced ports are those that can return a value even if no sequence happened through them, used for constants, variables, etc. + 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 true; } + 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)=0; //do a step, return which sequence port to go out + + Ref<VisualScriptNode> get_base_node() { return Ref<VisualScriptNode>( base ); } + + VisualScriptNodeInstance(); virtual ~VisualScriptNodeInstance(); }; @@ -112,6 +175,7 @@ public: private: +friend class VisualScriptInstance; StringName base_type; struct Argument { @@ -133,6 +197,9 @@ private: int function_id; + Vector2 scroll; + + Function() { function_id=-1; } }; @@ -146,8 +213,18 @@ private: Map<StringName,Function> functions; Map<StringName,Variable> variables; + Map<StringName,StringName> script_variable_remap; Map<StringName,Vector<Argument> > custom_signals; + Map<Object*,VisualScriptInstance*> instances; + +#ifdef TOOLS_ENABLED + Set<PlaceHolderScriptInstance*> placeholders; + //void _update_placeholder(PlaceHolderScriptInstance *p_placeholder); + virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder); + void _update_placeholders(); +#endif + void _set_variable_info(const StringName& p_name,const Dictionary& p_info); Dictionary _get_variable_info(const StringName& p_name) const; @@ -166,12 +243,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; @@ -242,21 +322,210 @@ public: virtual bool get_property_default_value(const StringName& p_property,Variant& r_value) const; virtual void get_method_list(List<MethodInfo> *p_list) const; + virtual bool has_method(const StringName& p_method) const; + virtual MethodInfo get_method_info(const StringName& p_method) const; + + VisualScript(); ~VisualScript(); }; +class VisualScriptInstance : public ScriptInstance { + Object *owner; + Ref<VisualScript> script; + + Map<StringName,Variant> variables; //using variable path, not script + Map<int,VisualScriptNodeInstance*> instances; + + struct Function { + int node; + int max_stack; + int trash_pos; + int return_pos; + int flow_stack_size; + int node_count; + int argument_count; + bool valid; + + struct UnsequencedGet { + VisualScriptNodeInstance* from; + int from_port; + int to_stack; + }; + + Vector<UnsequencedGet> unsequenced_gets; + + }; + + Map<StringName,Function> functions; + + Vector<Variant> default_values; + int max_input_args,max_output_args; + + StringName source; + + Variant _call_internal(const StringName& p_method, void* p_stack,int p_stack_size, VisualScriptNodeInstance* p_node, int p_flow_stack_pos, bool p_resuming_yield,Variant::CallError &r_error); + + + //Map<StringName,Function> functions; +friend class VisualScriptFunctionState; //for yield +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; + virtual void get_property_list(List<PropertyInfo> *p_properties) const; + virtual Variant::Type get_property_type(const StringName& p_name,bool *r_is_valid=NULL) const; + + virtual void get_method_list(List<MethodInfo> *p_list) const; + virtual bool has_method(const StringName& p_method) const; + virtual Variant call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error); + virtual void notification(int p_notification); + + bool set_variable(const StringName& p_variable,const Variant& p_value) { + + Map<StringName,Variant>::Element *E=variables.find(p_variable); + if (!E) + return false; + + E->get()=p_value; + return true; + } + + bool get_variable(const StringName& p_variable,Variant* r_variable) const { + + const Map<StringName,Variant>::Element *E=variables.find(p_variable); + if (!E) + return false; + + *r_variable=E->get(); + return true; + + } + + virtual Ref<Script> get_script() const; + + _FORCE_INLINE_ VisualScript *get_script_ptr() { return script.ptr(); } + _FORCE_INLINE_ Object *get_owner_ptr() { return owner; } + + void create(const Ref<VisualScript>& p_script,Object *p_owner); + + virtual ScriptLanguage *get_language(); + + VisualScriptInstance(); + ~VisualScriptInstance(); +}; + + +class VisualScriptFunctionState : public Reference { + + OBJ_TYPE(VisualScriptFunctionState,Reference); +friend class VisualScriptInstance; + + ObjectID instance_id; + ObjectID script_id; + VisualScriptInstance *instance; + StringName function; + Vector<uint8_t> stack; + int working_mem_index; + int variant_stack_size; + VisualScriptNodeInstance *node; + int flow_stack_pos; + + Variant _signal_callback(const Variant** p_args, int p_argcount, Variant::CallError& r_error); +protected: + static void _bind_methods(); +public: + + void connect_to_signal(Object* p_obj,const String& p_signal,Array p_binds); + bool is_valid() const; + Variant resume(Array p_args); + VisualScriptFunctionState(); + ~VisualScriptFunctionState(); +}; + + typedef Ref<VisualScriptNode> (*VisualScriptNodeRegisterFunc)(const String& p_type); 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; + StringName _get_output_port_unsequenced; + StringName _step; + StringName _subcall; static VisualScriptLanguage* singleton; + 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 */ @@ -270,7 +539,7 @@ public: virtual void get_reserved_words(List<String> *p_words) const; virtual void get_comment_delimiters(List<String> *p_delimiters) const; virtual void get_string_delimiters(List<String> *p_delimiters) const; - virtual String get_template(const String& p_class_name, const String& p_base_class_name) const; + virtual Ref<Script> get_template(const String& p_class_name, const String& p_base_class_name) const; virtual bool validate(const String& p_script, int &r_line_error,int &r_col_error,String& r_test_error, const String& p_path="",List<String> *r_functions=NULL) const; virtual Script *create_script() const; virtual bool has_named_classes() const; @@ -313,6 +582,7 @@ public: VisualScriptLanguage(); + ~VisualScriptLanguage(); }; diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp index 58edafd963..e813d9ea84 100644 --- a/modules/visual_script/visual_script_builtin_funcs.cpp +++ b/modules/visual_script/visual_script_builtin_funcs.cpp @@ -1,5 +1,11 @@ #include "visual_script_builtin_funcs.h" - +#include "math_funcs.h" +#include "object_type_db.h" +#include "reference.h" +#include "func_ref.h" +#include "os/os.h" +#include "variant_parser.h" +#include "io/marshalls.h" const char* VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX]={ "sin", @@ -538,12 +544,550 @@ VisualScriptBuiltinFunc::BuiltinFunc VisualScriptBuiltinFunc::get_func() { } +#define VALIDATE_ARG_NUM(m_arg) \ + if (!p_inputs[m_arg]->is_num()) {\ + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;\ + r_error.argument=m_arg;\ + r_error.expected=Variant::REAL;\ + return 0;\ + } + +class VisualScriptNodeInstanceBuiltinFunc : public VisualScriptNodeInstance { +public: + + VisualScriptBuiltinFunc *node; + VisualScriptInstance *instance; + + VisualScriptBuiltinFunc::BuiltinFunc func; + + + //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 true; } + + 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) { + + switch(func) { + case VisualScriptBuiltinFunc::MATH_SIN: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::sin(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_COS: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::cos(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_TAN: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::tan(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_SINH: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::sinh(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_COSH: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::cosh(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_TANH: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::tanh(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ASIN: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::asin(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ACOS: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::acos(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ATAN: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::atan(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ATAN2: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *p_outputs[0]=Math::atan2(*p_inputs[0],*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_SQRT: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::sqrt(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_FMOD: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *p_outputs[0]=Math::fmod(*p_inputs[0],*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_FPOSMOD: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *p_outputs[0]=Math::fposmod(*p_inputs[0],*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_FLOOR: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::floor(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_CEIL: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::ceil(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ROUND: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::round(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ABS: { + + if (p_inputs[0]->get_type()==Variant::INT) { + + int64_t i = *p_inputs[0]; + *p_outputs[0]=ABS(i); + } else if (p_inputs[0]->get_type()==Variant::REAL) { + + real_t r = *p_inputs[0]; + *p_outputs[0]=Math::abs(r); + } else { + + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::REAL; + + } + } break; + case VisualScriptBuiltinFunc::MATH_SIGN: { + + if (p_inputs[0]->get_type()==Variant::INT) { + + int64_t i = *p_inputs[0]; + *p_outputs[0]= i < 0 ? -1 : ( i > 0 ? +1 : 0); + } else if (p_inputs[0]->get_type()==Variant::REAL) { + + real_t r = *p_inputs[0]; + *p_outputs[0]= r < 0.0 ? -1.0 : ( r > 0.0 ? +1.0 : 0.0); + } else { + + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::REAL; + + } + } break; + case VisualScriptBuiltinFunc::MATH_POW: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *p_outputs[0]=Math::pow(*p_inputs[0],*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_LOG: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::log(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_EXP: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::exp(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ISNAN: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::is_nan(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ISINF: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::is_inf(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_EASE: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *p_outputs[0]=Math::ease(*p_inputs[0],*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_DECIMALS: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::step_decimals(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_STEPIFY: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *p_outputs[0]=Math::stepify(*p_inputs[0],*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_LERP: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); + *p_outputs[0]=Math::lerp(*p_inputs[0],*p_inputs[1],*p_inputs[2]); + } break; + case VisualScriptBuiltinFunc::MATH_DECTIME: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); + *p_outputs[0]=Math::dectime(*p_inputs[0],*p_inputs[1],*p_inputs[2]); + } break; + case VisualScriptBuiltinFunc::MATH_RANDOMIZE: { + Math::randomize(); + + } break; + case VisualScriptBuiltinFunc::MATH_RAND: { + *p_outputs[0]=Math::rand(); + } break; + case VisualScriptBuiltinFunc::MATH_RANDF: { + *p_outputs[0]=Math::randf(); + } break; + case VisualScriptBuiltinFunc::MATH_RANDOM: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *p_outputs[0]=Math::random(*p_inputs[0],*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_SEED: { + + VALIDATE_ARG_NUM(0); + uint32_t seed=*p_inputs[0]; + Math::seed(seed); + + } break; + case VisualScriptBuiltinFunc::MATH_RANDSEED: { + + VALIDATE_ARG_NUM(0); + uint32_t seed=*p_inputs[0]; + int ret = Math::rand_from_seed(&seed); + Array reta; + reta.push_back(ret); + reta.push_back(seed); + *p_outputs[0]=reta; + + } break; + case VisualScriptBuiltinFunc::MATH_DEG2RAD: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::deg2rad(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_RAD2DEG: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::rad2deg(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_LINEAR2DB: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::linear2db(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_DB2LINEAR: { + + VALIDATE_ARG_NUM(0); + *p_outputs[0]=Math::db2linear(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::LOGIC_MAX: { + + if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT) { + + int64_t a = *p_inputs[0]; + int64_t b = *p_inputs[1]; + *p_outputs[0]=MAX(a,b); + } else { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + + real_t a = *p_inputs[0]; + real_t b = *p_inputs[1]; + + *p_outputs[0]=MAX(a,b); + } + + } break; + case VisualScriptBuiltinFunc::LOGIC_MIN: { + + if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT) { + + int64_t a = *p_inputs[0]; + int64_t b = *p_inputs[1]; + *p_outputs[0]=MIN(a,b); + } else { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + + real_t a = *p_inputs[0]; + real_t b = *p_inputs[1]; + + *p_outputs[0]=MIN(a,b); + } + } break; + case VisualScriptBuiltinFunc::LOGIC_CLAMP: { + + if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT && p_inputs[2]->get_type()==Variant::INT) { + + int64_t a = *p_inputs[0]; + int64_t b = *p_inputs[1]; + int64_t c = *p_inputs[2]; + *p_outputs[0]=CLAMP(a,b,c); + } else { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); + + real_t a = *p_inputs[0]; + real_t b = *p_inputs[1]; + real_t c = *p_inputs[2]; + + *p_outputs[0]=CLAMP(a,b,c); + } + } break; + case VisualScriptBuiltinFunc::LOGIC_NEAREST_PO2: { + + VALIDATE_ARG_NUM(0); + int64_t num = *p_inputs[0]; + *p_outputs[0] = nearest_power_of_2(num); + } break; + case VisualScriptBuiltinFunc::OBJ_WEAKREF: { + + if (p_inputs[0]->get_type()!=Variant::OBJECT) { + + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::OBJECT; + + return 0; + + } + + if (p_inputs[0]->is_ref()) { + + REF r = *p_inputs[0]; + if (!r.is_valid()) { + + return 0; + } + + Ref<WeakRef> wref = memnew( WeakRef ); + wref->set_ref(r); + *p_outputs[0]=wref; + } else { + Object *obj = *p_inputs[0]; + if (!obj) { + + return 0; + } + Ref<WeakRef> wref = memnew( WeakRef ); + wref->set_obj(obj); + *p_outputs[0]=wref; + } + + + + + } break; + case VisualScriptBuiltinFunc::FUNC_FUNCREF: { + + if (p_inputs[0]->get_type()!=Variant::OBJECT) { + + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::OBJECT; + + return 0; + + } + if (p_inputs[1]->get_type()!=Variant::STRING && p_inputs[1]->get_type()!=Variant::NODE_PATH) { + + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=1; + r_error.expected=Variant::STRING; + + return 0; + + } + + Ref<FuncRef> fr = memnew( FuncRef); + + fr->set_instance(*p_inputs[0]); + fr->set_function(*p_inputs[1]); + + *p_outputs[0]=fr; + + } break; + case VisualScriptBuiltinFunc::TYPE_CONVERT: { + + VALIDATE_ARG_NUM(1); + int type=*p_inputs[1]; + if (type<0 || type>=Variant::VARIANT_MAX) { + + *p_outputs[0]=RTR("Invalid type argument to convert(), use TYPE_* constants."); + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::INT; + return 0; + + } else { + + + *p_outputs[0]=Variant::construct(Variant::Type(type),p_inputs,1,r_error); + } + } break; + case VisualScriptBuiltinFunc::TYPE_OF: { -VisualScriptNodeInstance* VisualScriptBuiltinFunc::instance(VScriptInstance* p_instance) { - return NULL; + *p_outputs[0] = p_inputs[0]->get_type(); + + } break; + case VisualScriptBuiltinFunc::TYPE_EXISTS: { + + + *p_outputs[0] = ObjectTypeDB::type_exists(*p_inputs[0]); + + } break; + case VisualScriptBuiltinFunc::TEXT_STR: { + + String str = *p_inputs[0]; + + *p_outputs[0]=str; + + } break; + case VisualScriptBuiltinFunc::TEXT_PRINT: { + + String str = *p_inputs[0]; + print_line(str); + + + } break; + + case VisualScriptBuiltinFunc::TEXT_PRINTERR: { + + String str = *p_inputs[0]; + + //str+="\n"; + OS::get_singleton()->printerr("%s\n",str.utf8().get_data()); + + + } break; + case VisualScriptBuiltinFunc::TEXT_PRINTRAW: { + String str = *p_inputs[0]; + + //str+="\n"; + OS::get_singleton()->print("%s",str.utf8().get_data()); + + + } break; + case VisualScriptBuiltinFunc::VAR_TO_STR: { + + String vars; + VariantWriter::write_to_string(*p_inputs[0],vars); + *p_outputs[0]=vars; + } break; + case VisualScriptBuiltinFunc::STR_TO_VAR: { + + if (p_inputs[0]->get_type()!=Variant::STRING) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::STRING; + + return 0; + } + + VariantParser::StreamString ss; + ss.s=*p_inputs[0]; + + String errs; + int line; + Error err = VariantParser::parse(&ss,*p_outputs[0],errs,line); + + if (err!=OK) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::STRING; + *p_outputs[0]="Parse error at line "+itos(line)+": "+errs; + return 0; + } + + } break; + case VisualScriptBuiltinFunc::VAR_TO_BYTES: { + + + ByteArray barr; + int len; + Error err = encode_variant(*p_inputs[0],NULL,len); + if (err) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::NIL; + *p_outputs[0]="Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID)."; + return 0; + } + + barr.resize(len); + { + ByteArray::Write w = barr.write(); + encode_variant(*p_inputs[0],w.ptr(),len); + + } + *p_outputs[0]=barr; + } break; + case VisualScriptBuiltinFunc::BYTES_TO_VAR: { + + if (p_inputs[0]->get_type()!=Variant::RAW_ARRAY) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::RAW_ARRAY; + + return 0; + } + + ByteArray varr=*p_inputs[0]; + Variant ret; + { + ByteArray::Read r=varr.read(); + Error err = decode_variant(ret,r.ptr(),varr.size(),NULL); + if (err!=OK) { + *p_outputs[0]=RTR("Not enough bytes for decoding bytes, or invalid format."); + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::RAW_ARRAY; + return 0; + } + + } + + *p_outputs[0]=ret; + + } break; + default: {} + } + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptBuiltinFunc::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceBuiltinFunc * instance = memnew(VisualScriptNodeInstanceBuiltinFunc ); + instance->node=this; + instance->instance=p_instance; + instance->func=func; + return instance; } + void VisualScriptBuiltinFunc::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_func","which"),&VisualScriptBuiltinFunc::set_func); @@ -577,66 +1121,66 @@ static Ref<VisualScriptNode> create_builtin_func_node(const String& p_name) { void register_visual_script_builtin_func_node() { - VisualScriptLanguage::singleton->add_register_func("functions/builtin/sin",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SIN>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/cos",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_COS>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/tan",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_TAN>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/sinh",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SINH>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/cosh",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_COSH>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/tanh",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_TANH>); - - VisualScriptLanguage::singleton->add_register_func("functions/builtin/asin",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ASIN>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/acos",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ACOS>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/atan",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ATAN>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/atan2",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ATAN2>); - - VisualScriptLanguage::singleton->add_register_func("functions/builtin/sqrt",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SQRT>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/fmod",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_FMOD>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/fposmod",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_FPOSMOD>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/floor",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_FLOOR>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/ceil",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_CEIL>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/round",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ROUND>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/abs",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ABS>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/sign",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SIGN>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/pow",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_POW>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/log",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LOG>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/exp",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_EXP>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/isnan",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ISNAN>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/isinf",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ISINF>); - - VisualScriptLanguage::singleton->add_register_func("functions/builtin/ease",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_EASE>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/decimals",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DECIMALS>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/stepify",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_STEPIFY>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/lerp",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LERP>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/dectime",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DECTIME>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/randomize",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDOMIZE>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/rand",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RAND>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/randf",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDF>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/random",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDOM>); - - VisualScriptLanguage::singleton->add_register_func("functions/builtin/seed",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SEED>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/randseed",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDSEED>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/deg2rad",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DEG2RAD>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/rad2deg",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RAD2DEG>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/linear2db",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LINEAR2DB>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/db2linear",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DB2LINEAR>); - - VisualScriptLanguage::singleton->add_register_func("functions/builtin/max",create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_MAX>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/min",create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_MIN>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/clamp",create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_CLAMP>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/nearest_po2",create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_NEAREST_PO2>); - - VisualScriptLanguage::singleton->add_register_func("functions/builtin/weakref",create_builtin_func_node<VisualScriptBuiltinFunc::OBJ_WEAKREF>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/funcref",create_builtin_func_node<VisualScriptBuiltinFunc::FUNC_FUNCREF>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/convert",create_builtin_func_node<VisualScriptBuiltinFunc::TYPE_CONVERT>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/typeof",create_builtin_func_node<VisualScriptBuiltinFunc::TYPE_OF>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/type_exists",create_builtin_func_node<VisualScriptBuiltinFunc::TYPE_EXISTS>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/str",create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_STR>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/print",create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINT>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/printerr",create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINTERR>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/printraw",create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINTRAW>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/var2str",create_builtin_func_node<VisualScriptBuiltinFunc::VAR_TO_STR>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/str2var",create_builtin_func_node<VisualScriptBuiltinFunc::STR_TO_VAR>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/var2bytes",create_builtin_func_node<VisualScriptBuiltinFunc::VAR_TO_BYTES>); - VisualScriptLanguage::singleton->add_register_func("functions/builtin/bytes2var",create_builtin_func_node<VisualScriptBuiltinFunc::BYTES_TO_VAR>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/sin",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SIN>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/cos",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_COS>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/tan",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_TAN>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/sinh",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SINH>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/cosh",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_COSH>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/tanh",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_TANH>); + + VisualScriptLanguage::singleton->add_register_func("functions/built_in/asin",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ASIN>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/acos",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ACOS>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/atan",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ATAN>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/atan2",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ATAN2>); + + VisualScriptLanguage::singleton->add_register_func("functions/built_in/sqrt",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SQRT>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/fmod",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_FMOD>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/fposmod",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_FPOSMOD>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/floor",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_FLOOR>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/ceil",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_CEIL>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/round",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ROUND>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/abs",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ABS>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/sign",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SIGN>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/pow",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_POW>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/log",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LOG>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/exp",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_EXP>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/isnan",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ISNAN>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/isinf",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ISINF>); + + VisualScriptLanguage::singleton->add_register_func("functions/built_in/ease",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_EASE>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/decimals",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DECIMALS>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/stepify",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_STEPIFY>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/lerp",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LERP>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/dectime",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DECTIME>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/randomize",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDOMIZE>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/rand",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RAND>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/randf",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDF>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/random",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDOM>); + + VisualScriptLanguage::singleton->add_register_func("functions/built_in/seed",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SEED>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/randseed",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDSEED>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/deg2rad",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DEG2RAD>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/rad2deg",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RAD2DEG>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/linear2db",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LINEAR2DB>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/db2linear",create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DB2LINEAR>); + + VisualScriptLanguage::singleton->add_register_func("functions/built_in/max",create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_MAX>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/min",create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_MIN>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/clamp",create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_CLAMP>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/nearest_po2",create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_NEAREST_PO2>); + + VisualScriptLanguage::singleton->add_register_func("functions/built_in/weakref",create_builtin_func_node<VisualScriptBuiltinFunc::OBJ_WEAKREF>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/funcref",create_builtin_func_node<VisualScriptBuiltinFunc::FUNC_FUNCREF>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/convert",create_builtin_func_node<VisualScriptBuiltinFunc::TYPE_CONVERT>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/typeof",create_builtin_func_node<VisualScriptBuiltinFunc::TYPE_OF>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/type_exists",create_builtin_func_node<VisualScriptBuiltinFunc::TYPE_EXISTS>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/str",create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_STR>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/print",create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINT>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/printerr",create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINTERR>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/printraw",create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINTRAW>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/var2str",create_builtin_func_node<VisualScriptBuiltinFunc::VAR_TO_STR>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/str2var",create_builtin_func_node<VisualScriptBuiltinFunc::STR_TO_VAR>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/var2bytes",create_builtin_func_node<VisualScriptBuiltinFunc::VAR_TO_BYTES>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/bytes2var",create_builtin_func_node<VisualScriptBuiltinFunc::BYTES_TO_VAR>); } diff --git a/modules/visual_script/visual_script_builtin_funcs.h b/modules/visual_script/visual_script_builtin_funcs.h index b4dbd4db39..ebf227a192 100644 --- a/modules/visual_script/visual_script_builtin_funcs.h +++ b/modules/visual_script/visual_script_builtin_funcs.h @@ -91,11 +91,12 @@ public: virtual String get_caption() const; virtual String get_text() const; + virtual String get_category() const { return "functions"; } void set_func(BuiltinFunc p_which); BuiltinFunc get_func(); - virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance); + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); VisualScriptBuiltinFunc(); }; diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index ad4f2be34c..0d97126e0a 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,6 +427,15 @@ 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_editor/color_"+node->get_category())) { + gnode->set_modulate(EditorSettings::get_singleton()->get("visual_script_editor/color_"+node->get_category())); + } gnode->set_meta("__vnode",node); gnode->set_name(itos(E->get())); @@ -551,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; } @@ -579,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); } @@ -656,6 +674,7 @@ void VisualScriptEditor::_member_selected() { revert_on_drag=edited_func; edited_func=selected; + _update_members(); _update_graph(); } @@ -1377,6 +1396,16 @@ bool VisualScriptEditor::can_drop_data_fw(const Point2& p_point,const Variant& p const_cast<VisualScriptEditor*>(this)->_show_hint("Hold Ctrl to drop a Setter, Shift+Ctrl to drop a Setter and copy the value."); #endif } + + if (String(d["type"])=="visual_script_variable_drag") { + +#ifdef OSX_ENABLED + const_cast<VisualScriptEditor*>(this)->_show_hint("Hold Meta to drop a Variable Setter."); +#else + const_cast<VisualScriptEditor*>(this)->_show_hint("Hold Ctrl to drop a Variable Setter."); +#endif + } + return true; } @@ -1448,6 +1477,11 @@ void VisualScriptEditor::drop_data_fw(const Point2& p_point,const Variant& p_dat if (d.has("type") && String(d["type"])=="visual_script_variable_drag") { +#ifdef OSX_ENABLED + bool use_set = Input::get_singleton()->is_key_pressed(KEY_META); +#else + bool use_set = Input::get_singleton()->is_key_pressed(KEY_CONTROL); +#endif Vector2 ofs = graph->get_scroll_ofs() + p_point; if (graph->is_using_snap()) { int snap = graph->get_snap(); @@ -1456,9 +1490,19 @@ void VisualScriptEditor::drop_data_fw(const Point2& p_point,const Variant& p_dat ofs/=EDSCALE; - Ref<VisualScriptVariable> vnode; - vnode.instance(); - vnode->set_variable(d["variable"]); + Ref<VisualScriptNode> vnode; + if (use_set) { + Ref<VisualScriptVariableSet> vnodes; + vnodes.instance(); + vnodes->set_variable(d["variable"]); + vnode=vnodes; + } else { + + Ref<VisualScriptVariableGet> vnodeg; + vnodeg.instance(); + vnodeg->set_variable(d["variable"]); + vnode=vnodeg; + } int new_id = script->get_available_id(); @@ -1775,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(){ @@ -1801,7 +1913,7 @@ void VisualScriptEditor::trim_trailing_whitespace(){ void VisualScriptEditor::ensure_focus(){ - + graph->grab_focus(); } void VisualScriptEditor::tag_saved_version(){ @@ -1816,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){ @@ -1842,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() { @@ -2137,6 +2317,60 @@ 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; + case EDIT_FIND_NODE_TYPE: { + //popup disappearing grabs focus to owner, so use call deferred + node_filter->call_deferred("grab_focus"); + node_filter->call_deferred("select_all"); + } break; + + } +} + void VisualScriptEditor::_bind_methods() { ObjectTypeDB::bind_method("_member_button",&VisualScriptEditor::_member_button); @@ -2157,6 +2391,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); @@ -2182,6 +2419,15 @@ 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()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/find_node_type"), EDIT_FIND_NODE_TYPE); + 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(); @@ -2203,7 +2449,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); @@ -2245,6 +2491,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")); @@ -2329,6 +2576,7 @@ VisualScriptEditor::VisualScriptEditor() { add_child(default_value_edit); default_value_edit->connect("variant_changed",this,"_default_value_changed"); + error_line=-1; } VisualScriptEditor::~VisualScriptEditor() { @@ -2347,9 +2595,28 @@ 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)); + EditorSettings::get_singleton()->set("visual_script_editor/color_custom",Color(0.8,1.0,1.0)); + + + 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); + +} 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..bd33f35739 100644 --- a/modules/visual_script/visual_script_editor.h +++ b/modules/visual_script/visual_script_editor.h @@ -22,6 +22,14 @@ class VisualScriptEditor : public ScriptEditorBase { }; + enum { + EDIT_DELETE_NODES, + EDIT_TOGGLE_BREAKPOINT, + EDIT_FIND_NODE_TYPE, + }; + + MenuButton *edit_menu; + Ref<VisualScript> script; Button *base_type_select; @@ -57,6 +65,8 @@ class VisualScriptEditor : public ScriptEditorBase { Label *select_func_text; + bool updating_graph; + void _show_hint(const String& p_hint); void _hide_timer(); @@ -88,7 +98,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 +142,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 +162,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 +171,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_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp index 83d975fbca..cb0ff4086c 100644 --- a/modules/visual_script/visual_script_flow_control.cpp +++ b/modules/visual_script/visual_script_flow_control.cpp @@ -1,4 +1,6 @@ #include "visual_script_flow_control.h" +#include "os/keyboard.h" +#include "globals.h" ////////////////////////////////////////// ////////////////RETURN//////////////////// @@ -93,9 +95,38 @@ void VisualScriptReturn::_bind_methods() { } -VisualScriptNodeInstance* VisualScriptReturn::instance(VScriptInstance* p_instance) { +class VisualScriptNodeInstanceReturn : public VisualScriptNodeInstance { +public: - return NULL; + VisualScriptReturn *node; + VisualScriptInstance *instance; + bool with_value; + + virtual int get_working_memory_size() const { return 1; } + //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 true; } + + 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) { + + if (with_value) { + *p_working_mem = *p_inputs[0]; + } else { + *p_working_mem = Variant(); + } + + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptReturn::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceReturn * instance = memnew(VisualScriptNodeInstanceReturn ); + instance->node=this; + instance->instance=p_instance; + instance->with_value=with_value; + return instance; } VisualScriptReturn::VisualScriptReturn() { @@ -174,9 +205,33 @@ void VisualScriptCondition::_bind_methods() { } -VisualScriptNodeInstance* VisualScriptCondition::instance(VScriptInstance* p_instance) { +class VisualScriptNodeInstanceCondition : public VisualScriptNodeInstance { +public: + + VisualScriptCondition *node; + VisualScriptInstance *instance; + + //virtual int get_working_memory_size() const { return 1; } + //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 true; } - return NULL; + 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) { + + if (p_inputs[0]->operator bool()) + return 0; + else + return 1; + } + + +}; + +VisualScriptNodeInstance* VisualScriptCondition::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceCondition * instance = memnew(VisualScriptNodeInstanceCondition ); + instance->node=this; + instance->instance=p_instance; + return instance; } VisualScriptCondition::VisualScriptCondition() { @@ -244,11 +299,36 @@ void VisualScriptWhile::_bind_methods() { } -VisualScriptNodeInstance* VisualScriptWhile::instance(VScriptInstance* p_instance) { +class VisualScriptNodeInstanceWhile : public VisualScriptNodeInstance { +public: - return NULL; -} + VisualScriptWhile *node; + VisualScriptInstance *instance; + + //virtual int get_working_memory_size() const { return 1; } + //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 true; } + + 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) { + bool keep_going = p_inputs[0]->operator bool(); + + if (keep_going) + return 0|STEP_FLAG_PUSH_STACK_BIT; + else + return 1; + } + + +}; + +VisualScriptNodeInstance* VisualScriptWhile::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceWhile * instance = memnew(VisualScriptNodeInstanceWhile ); + instance->node=this; + instance->instance=p_instance; + return instance; +} VisualScriptWhile::VisualScriptWhile() { } @@ -316,9 +396,79 @@ void VisualScriptIterator::_bind_methods() { } -VisualScriptNodeInstance* VisualScriptIterator::instance(VScriptInstance* p_instance) { +class VisualScriptNodeInstanceIterator : public VisualScriptNodeInstance { +public: + + VisualScriptIterator *node; + VisualScriptInstance *instance; + + virtual int get_working_memory_size() const { return 2; } + //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 true; } + + 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) { + + if (p_start_mode==START_MODE_BEGIN_SEQUENCE) { + p_working_mem[0]=*p_inputs[0]; + bool valid; + bool can_iter = p_inputs[0]->iter_init(p_working_mem[1],valid); + + if (!valid) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str=RTR("Input type not iterable: ")+Variant::get_type_name(p_inputs[0]->get_type()); + return 0; + } + + if (!can_iter) + return 1; //nothing to iterate + + + *p_outputs[0]=p_working_mem[0].iter_get( p_working_mem[1],valid); + + if (!valid) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str=RTR("Iterator became invalid"); + return 0; + } + + + } else { //continue sequence + + bool valid; + bool can_iter = p_working_mem[0].iter_next(p_working_mem[1],valid); + + if (!valid) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str=RTR("Iterator became invalid: ")+Variant::get_type_name(p_inputs[0]->get_type()); + return 0; + } + + if (!can_iter) + return 1; //nothing to iterate + + + *p_outputs[0]=p_working_mem[0].iter_get( p_working_mem[1],valid); - return NULL; + if (!valid) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str=RTR("Iterator became invalid"); + return 0; + } + + } + + return 0|STEP_FLAG_PUSH_STACK_BIT; //go around + } + + +}; + +VisualScriptNodeInstance* VisualScriptIterator::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceIterator * instance = memnew(VisualScriptNodeInstanceIterator ); + instance->node=this; + instance->instance=p_instance; + return instance; } VisualScriptIterator::VisualScriptIterator() { @@ -396,16 +546,1122 @@ void VisualScriptSequence::_bind_methods() { } -VisualScriptNodeInstance* VisualScriptSequence::instance(VScriptInstance* p_instance) { +class VisualScriptNodeInstanceSequence : public VisualScriptNodeInstance { +public: - return NULL; -} + VisualScriptSequence *node; + VisualScriptInstance *instance; + int steps; + + virtual int get_working_memory_size() const { return 1; } + //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 true; } + + 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) { + + if (p_start_mode==START_MODE_BEGIN_SEQUENCE) { + p_working_mem[0]=0; + } + + int step = p_working_mem[0]; + + *p_outputs[0]=step; + + if (step+1==steps) + return step; + else { + p_working_mem[0]=step+1; + return step|STEP_FLAG_PUSH_STACK_BIT; + } + + } + + +}; + +VisualScriptNodeInstance* VisualScriptSequence::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceSequence * instance = memnew(VisualScriptNodeInstanceSequence ); + instance->node=this; + instance->instance=p_instance; + instance->steps=steps; + return instance; +} VisualScriptSequence::VisualScriptSequence() { steps=1; } + +////////////////////////////////////////// +////////////////EVENT TYPE FILTER/////////// +////////////////////////////////////////// + +static const char* event_type_names[InputEvent::TYPE_MAX]={ + "None", + "Key", + "MouseMotion", + "MouseButton", + "JoystickMotion", + "JoystickButton", + "ScreenTouch", + "ScreenDrag", + "Action" +}; + +int VisualScriptInputSelector::get_output_sequence_port_count() const { + + return InputEvent::TYPE_MAX; +} + +bool VisualScriptInputSelector::has_input_sequence_port() const{ + + return true; +} + +int VisualScriptInputSelector::get_input_value_port_count() const{ + + + return 1; +} +int VisualScriptInputSelector::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptInputSelector::get_output_sequence_port_text(int p_port) const { + + return event_type_names[p_port]; +} + +PropertyInfo VisualScriptInputSelector::get_input_value_port_info(int p_idx) const{ + + return PropertyInfo(Variant::INPUT_EVENT,"event"); +} + +PropertyInfo VisualScriptInputSelector::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(Variant::INPUT_EVENT,""); +} + + +String VisualScriptInputSelector::get_caption() const { + + return "InputSelector"; +} + +String VisualScriptInputSelector::get_text() const { + + return ""; +} + + +class VisualScriptNodeInstanceInputSelector : public VisualScriptNodeInstance { +public: + + VisualScriptInstance* instance; + InputEvent::Type type; + + //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) { + + if (p_inputs[0]->get_type()!=Variant::INPUT_EVENT) { + r_error_str="Input value not of type event"; + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + return 0; + } + + InputEvent event = *p_inputs[0]; + + *p_outputs[0] = event; + + return event.type; + } + + +}; + +VisualScriptNodeInstance* VisualScriptInputSelector::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceInputSelector * instance = memnew(VisualScriptNodeInstanceInputSelector ); + instance->instance=p_instance; + return instance; +} + + + +void VisualScriptInputSelector::_bind_methods() { + + +} + +VisualScriptInputSelector::VisualScriptInputSelector() { + + +} + +////////////////////////////////////////// +////////////////EVENT ACTION FILTER/////////// +////////////////////////////////////////// + + +int VisualScriptInputFilter::get_output_sequence_port_count() const { + + return filters.size(); +} + +bool VisualScriptInputFilter::has_input_sequence_port() const{ + + return true; +} + +int VisualScriptInputFilter::get_input_value_port_count() const{ + + + return 1; +} +int VisualScriptInputFilter::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptInputFilter::get_output_sequence_port_text(int p_port) const { + + String text; + + switch(filters[p_port].type) { + case InputEvent::NONE: { + text="None"; + } break; + case InputEvent::KEY: { + + InputEventKey k = filters[p_port].key; + + if (k.scancode==0 && k.unicode==0) { + text="No Key"; + } else { + if (k.scancode!=0) { + text="KeyCode: "+keycode_get_string(k.scancode); + } else if (k.unicode!=0) { + text="Uniode: "+String::chr(k.unicode); + } + + if (k.pressed) + text+=", Pressed"; + else + text+=", Released"; + + if (k.echo) + text+=", Echo"; + if (k.mod.alt) + text="Alt+"+text; + if (k.mod.shift) + text="Shift+"+text; + if (k.mod.control) + text="Ctrl+"+text; + if (k.mod.meta) + text="Meta+"+text; + } + + } break; + case InputEvent::MOUSE_MOTION: { + InputEventMouseMotion mm = filters[p_port].mouse_motion; + text="Mouse Motion"; + + String b = "Left,Right,Middle,WheelUp,WheelDown,WheelLeft,WheelRight"; + + for(int i=0;i<7;i++) { + if (mm.button_mask&(1<<i)) { + text=b.get_slice(",",i)+"+"+text; + } + } + if (mm.mod.alt) + text="Alt+"+text; + if (mm.mod.shift) + text="Shift+"+text; + if (mm.mod.control) + text="Ctrl+"+text; + if (mm.mod.meta) + text="Meta+"+text; + } break; + case InputEvent::MOUSE_BUTTON: { + + InputEventMouseButton mb = filters[p_port].mouse_button; + + String b = "Any,Left,Right,Middle,WheelUp,WheelDown,WheelLeft,WheelRight"; + + text=b.get_slice(",",mb.button_index)+" Mouse Button"; + + if (mb.pressed) + text+=", Pressed"; + else + text+=", Released"; + + if (mb.doubleclick) + text+=", DblClick"; + if (mb.mod.alt) + text="Alt+"+text; + if (mb.mod.shift) + text="Shift+"+text; + if (mb.mod.control) + text="Ctrl+"+text; + if (mb.mod.meta) + text="Meta+"+text; + + + } break; + case InputEvent::JOYSTICK_MOTION: { + + InputEventJoystickMotion jm = filters[p_port].joy_motion; + + text="JoyMotion Axis "+itos(jm.axis>>1); + if (jm.axis&1) + text+=" > "+rtos(jm.axis_value); + else + text+=" < "+rtos(-jm.axis_value); + + } break; + case InputEvent::JOYSTICK_BUTTON: { + InputEventJoystickButton jb = filters[p_port].joy_button; + + text="JoyButton "+itos(jb.button_index); + if (jb.pressed) + text+=", Pressed"; + else + text+=", Released"; + } break; + case InputEvent::SCREEN_TOUCH: { + InputEventScreenTouch sd = filters[p_port].screen_touch; + + text="Touch Finger "+itos(sd.index); + if (sd.pressed) + text+=", Pressed"; + else + text+=", Released"; + } break; + case InputEvent::SCREEN_DRAG: { + InputEventScreenDrag sd = filters[p_port].screen_drag; + text="Drag Finger "+itos(sd.index); + } break; + case InputEvent::ACTION: { + + + List<PropertyInfo> pinfo; + Globals::get_singleton()->get_property_list(&pinfo); + int index=1; + + text="No Action"; + for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { + const PropertyInfo &pi=E->get(); + + if (!pi.name.begins_with("input/")) + continue; + + + if (filters[p_port].action.action==index) { + text="Action "+pi.name.substr(pi.name.find("/")+1,pi.name.length()); + break; + } + index++; + } + + if (filters[p_port].action.pressed) + text+=", Pressed"; + else + text+=", Released"; + + + } break; + } + + + + return text+" - "+itos(p_port); +} + +PropertyInfo VisualScriptInputFilter::get_input_value_port_info(int p_idx) const{ + + return PropertyInfo(Variant::INPUT_EVENT,"event"); +} + +PropertyInfo VisualScriptInputFilter::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(Variant::INPUT_EVENT,""); +} + + +String VisualScriptInputFilter::get_caption() const { + + return "InputFilter"; +} + +String VisualScriptInputFilter::get_text() const { + + return ""; +} + + + +bool VisualScriptInputFilter::_set(const StringName& p_name, const Variant& p_value) { + + if (p_name=="filter_count") { + filters.resize(p_value); + _change_notify(); + ports_changed_notify(); + return true; + } + + + if (String(p_name).begins_with("filter_")) { + + int idx = String(p_name).replace_first("filters_","").get_slice("/",0).to_int(); + + ERR_FAIL_INDEX_V(idx,filters.size(),false); + + String what = String(p_name).get_slice("/",1); + + + if (what=="type") { + filters[idx]=InputEvent(); + filters[idx].type=InputEvent::Type(int(p_value)); + if (filters[idx].type==InputEvent::JOYSTICK_MOTION) { + filters[idx].joy_motion.axis_value=0.5; //for treshold + } else if (filters[idx].type==InputEvent::KEY) { + filters[idx].key.pressed=true; //put these as true to make it more user friendly + } else if (filters[idx].type==InputEvent::MOUSE_BUTTON) { + filters[idx].mouse_button.pressed=true; + } else if (filters[idx].type==InputEvent::JOYSTICK_BUTTON) { + filters[idx].joy_button.pressed=true; + } else if (filters[idx].type==InputEvent::SCREEN_TOUCH) { + filters[idx].screen_touch.pressed=true; + } else if (filters[idx].type==InputEvent::ACTION) { + filters[idx].action.pressed=true; + } + _change_notify(); + ports_changed_notify(); + + return true; + } + if (what=="device") { + filters[idx].device=p_value; + ports_changed_notify(); + return true; + } + + switch(filters[idx].type) { + + case InputEvent::KEY: { + + if (what=="scancode") { + String sc = p_value; + if (sc==String()) { + filters[idx].key.scancode=0; + } else { + filters[idx].key.scancode=find_keycode(p_value); + } + + } else if (what=="unicode") { + + String uc = p_value; + + if (uc==String()) { + filters[idx].key.unicode=0; + } else { + filters[idx].key.unicode=uc[0]; + } + + } else if (what=="pressed") { + + filters[idx].key.pressed=p_value; + } else if (what=="echo") { + + filters[idx].key.echo=p_value; + + } else if (what=="mod_alt") { + filters[idx].key.mod.alt=p_value; + + } else if (what=="mod_shift") { + filters[idx].key.mod.shift=p_value; + + } else if (what=="mod_ctrl") { + filters[idx].key.mod.control=p_value; + + } else if (what=="mod_meta") { + filters[idx].key.mod.meta=p_value; + } else { + return false; + } + ports_changed_notify(); + + return true; + } break; + case InputEvent::MOUSE_MOTION: { + + + if (what=="button_mask") { + filters[idx].mouse_motion.button_mask=p_value; + + } else if (what=="mod_alt") { + filters[idx].mouse_motion.mod.alt=p_value; + + } else if (what=="mod_shift") { + filters[idx].mouse_motion.mod.shift=p_value; + + } else if (what=="mod_ctrl") { + filters[idx].mouse_motion.mod.control=p_value; + + } else if (what=="mod_meta") { + filters[idx].mouse_motion.mod.meta=p_value; + } else { + return false; + } + + ports_changed_notify(); + return true; + + } break; + case InputEvent::MOUSE_BUTTON: { + + if (what=="button_index") { + filters[idx].mouse_button.button_index=p_value; + } else if (what=="pressed") { + filters[idx].mouse_button.pressed=p_value; + } else if (what=="doubleclicked") { + filters[idx].mouse_button.doubleclick=p_value; + + } else if (what=="mod_alt") { + filters[idx].mouse_button.mod.alt=p_value; + + } else if (what=="mod_shift") { + filters[idx].mouse_button.mod.shift=p_value; + + } else if (what=="mod_ctrl") { + filters[idx].mouse_button.mod.control=p_value; + + } else if (what=="mod_meta") { + filters[idx].mouse_button.mod.meta=p_value; + } else { + return false; + } + ports_changed_notify(); + return true; + + } break; + case InputEvent::JOYSTICK_MOTION: { + + if (what=="axis") { + filters[idx].joy_motion.axis=int(p_value)<<1|filters[idx].joy_motion.axis; + } else if (what=="mode") { + filters[idx].joy_motion.axis|=int(p_value); + } else if (what=="treshold") { + filters[idx].joy_motion.axis_value=p_value; + } else { + return false; + } + ports_changed_notify(); + return true; + + + } break; + case InputEvent::JOYSTICK_BUTTON: { + + if (what=="button_index") { + filters[idx].joy_button.button_index=p_value; + } else if (what=="pressed") { + filters[idx].joy_button.pressed=p_value; + } else { + return false; + } + ports_changed_notify(); + return true; + + } break; + case InputEvent::SCREEN_TOUCH: { + + if (what=="finger_index") { + filters[idx].screen_touch.index=p_value; + } else if (what=="pressed") { + filters[idx].screen_touch.pressed=p_value; + } else { + return false; + } + ports_changed_notify(); + return true; + } break; + case InputEvent::SCREEN_DRAG: { + if (what=="finger_index") { + filters[idx].screen_drag.index=p_value; + } else { + return false; + } + ports_changed_notify(); + return true; + } break; + case InputEvent::ACTION: { + + + if (what=="action_name") { + + List<PropertyInfo> pinfo; + Globals::get_singleton()->get_property_list(&pinfo); + int index=1; + + for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { + const PropertyInfo &pi=E->get(); + + if (!pi.name.begins_with("input/")) + continue; + + String name = pi.name.substr(pi.name.find("/")+1,pi.name.length()); + if (name==String(p_value)) { + + filters[idx].action.action=index; + ports_changed_notify(); + return true; + } + + index++; + } + + filters[idx].action.action=0; + ports_changed_notify(); + + return false; + + } else if (what=="pressed") { + + filters[idx].action.pressed=p_value; + ports_changed_notify(); + return true; + } + + + } break; + + } + } + return false; +} + +bool VisualScriptInputFilter::_get(const StringName& p_name,Variant &r_ret) const{ + + if (p_name=="filter_count") { + r_ret=filters.size(); + return true; + } + + + if (String(p_name).begins_with("filter_")) { + + int idx = String(p_name).replace_first("filters_","").get_slice("/",0).to_int(); + + ERR_FAIL_INDEX_V(idx,filters.size(),false); + + String what = String(p_name).get_slice("/",1); + + + if (what=="type") { + r_ret=filters[idx].type; + return true; + } + if (what=="device") { + r_ret=filters[idx].device; + return true; + } + + switch(filters[idx].type) { + + case InputEvent::KEY: { + + if (what=="scancode") { + if (filters[idx].key.scancode==0) + r_ret=String(); + else { + + r_ret=keycode_get_string(filters[idx].key.scancode); + } + + } else if (what=="unicode") { + + + if (filters[idx].key.unicode==0) { + r_ret=String(); + } else { + CharType str[2]={ (CharType)filters[idx].key.unicode, 0}; + r_ret=String(str); + } + + } else if (what=="pressed") { + + r_ret=filters[idx].key.pressed; + } else if (what=="echo") { + + r_ret=filters[idx].key.echo; + + } else if (what=="mod_alt") { + r_ret=filters[idx].key.mod.alt; + + } else if (what=="mod_shift") { + r_ret=filters[idx].key.mod.shift; + + } else if (what=="mod_ctrl") { + r_ret=filters[idx].key.mod.control; + + } else if (what=="mod_meta") { + r_ret=filters[idx].key.mod.meta; + } else { + return false; + } + + return true; + } break; + case InputEvent::MOUSE_MOTION: { + + + if (what=="button_mask") { + r_ret=filters[idx].mouse_motion.button_mask; + + } else if (what=="mod_alt") { + r_ret=filters[idx].mouse_motion.mod.alt; + + } else if (what=="mod_shift") { + r_ret=filters[idx].mouse_motion.mod.shift; + + } else if (what=="mod_ctrl") { + r_ret=filters[idx].mouse_motion.mod.control; + + } else if (what=="mod_meta") { + r_ret=filters[idx].mouse_motion.mod.meta; + } else { + return false; + } + + return true; + + } break; + case InputEvent::MOUSE_BUTTON: { + + if (what=="button_index") { + r_ret=filters[idx].mouse_button.button_index; + } else if (what=="pressed") { + r_ret=filters[idx].mouse_button.pressed; + } else if (what=="doubleclicked") { + r_ret=filters[idx].mouse_button.doubleclick; + + } else if (what=="mod_alt") { + r_ret=filters[idx].mouse_button.mod.alt; + + } else if (what=="mod_shift") { + r_ret=filters[idx].mouse_button.mod.shift; + + } else if (what=="mod_ctrl") { + r_ret=filters[idx].mouse_button.mod.control; + + } else if (what=="mod_meta") { + r_ret=filters[idx].mouse_button.mod.meta; + } else { + return false; + } + return true; + + } break; + case InputEvent::JOYSTICK_MOTION: { + + if (what=="axis_index") { + r_ret=filters[idx].joy_motion.axis>>1; + } else if (what=="mode") { + r_ret=filters[idx].joy_motion.axis&1; + } else if (what=="treshold") { + r_ret=filters[idx].joy_motion.axis_value; + } else { + return false; + } + return true; + + + } break; + case InputEvent::JOYSTICK_BUTTON: { + + if (what=="button_index") { + r_ret=filters[idx].joy_button.button_index; + } else if (what=="pressed") { + r_ret=filters[idx].joy_button.pressed; + } else { + return false; + } + return true; + + } break; + case InputEvent::SCREEN_TOUCH: { + + if (what=="finger_index") { + r_ret=filters[idx].screen_touch.index; + } else if (what=="pressed") { + r_ret=filters[idx].screen_touch.pressed; + } else { + return false; + } + return true; + } break; + case InputEvent::SCREEN_DRAG: { + if (what=="finger_index") { + r_ret=filters[idx].screen_drag.index; + } else { + return false; + } + return true; + } break; + case InputEvent::ACTION: { + + + if (what=="action_name") { + + List<PropertyInfo> pinfo; + Globals::get_singleton()->get_property_list(&pinfo); + int index=1; + + for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { + const PropertyInfo &pi=E->get(); + + if (!pi.name.begins_with("input/")) + continue; + + + if (filters[idx].action.action==index) { + r_ret=pi.name.substr(pi.name.find("/")+1,pi.name.length()); + return true; + } + index++; + } + + r_ret="None"; //no index + return false; + + } else if (what=="pressed") { + + r_ret=filters[idx].action.pressed; + return true; + } + + + } break; + + } + } + return false; +} +void VisualScriptInputFilter::_get_property_list( List<PropertyInfo> *p_list) const { + + p_list->push_back(PropertyInfo(Variant::INT,"filter_count",PROPERTY_HINT_RANGE,"0,64")); + + String et; + for(int i=0;i<InputEvent::TYPE_MAX;i++) { + if (i>0) + et+=","; + + et+=event_type_names[i]; + } + + String kc; + String actions; + + + + for(int i=0;i<filters.size();i++) { + + String base = "filter_"+itos(i)+"/"; + p_list->push_back(PropertyInfo(Variant::INT,base+"type",PROPERTY_HINT_ENUM,et)); + p_list->push_back(PropertyInfo(Variant::INT,base+"device")); + switch(filters[i].type) { + + case InputEvent::NONE: { + + } break; + case InputEvent::KEY: { + if (kc==String()) { + int kcc = keycode_get_count(); + kc="None"; + for(int i=0;i<kcc;i++) { + kc+=","; + kc+=String(keycode_get_name_by_index(i)); + } + } + p_list->push_back(PropertyInfo(Variant::STRING,base+"scancode",PROPERTY_HINT_ENUM,kc)); + p_list->push_back(PropertyInfo(Variant::STRING,base+"unicode")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"pressed")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"echo")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_alt")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_shift")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_ctrl")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_meta")); + + + } break; + case InputEvent::MOUSE_MOTION: { + p_list->push_back(PropertyInfo(Variant::INT,base+"button_mask",PROPERTY_HINT_FLAGS,"Left,Right,Middle,WheelUp,WheelDown,WheelLeft,WheelRight")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_alt")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_shift")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_ctrl")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_meta")); + + } break; + case InputEvent::MOUSE_BUTTON: { + p_list->push_back(PropertyInfo(Variant::INT,base+"button_index",PROPERTY_HINT_ENUM,"Any,Left,Right,Middle,WheelUp,WheelDown,WheelLeft,WheelRight")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"pressed")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"doubleclicked")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_alt")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_shift")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_ctrl")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"mod_meta")); + + } break; + case InputEvent::JOYSTICK_MOTION: { + + p_list->push_back(PropertyInfo(Variant::INT,base+"axis_index")); + p_list->push_back(PropertyInfo(Variant::INT,base+"mode",PROPERTY_HINT_ENUM,"Min,Max")); + p_list->push_back(PropertyInfo(Variant::REAL,base+"treshold",PROPERTY_HINT_RANGE,"0,1,0.01")); + } break; + case InputEvent::JOYSTICK_BUTTON: { + p_list->push_back(PropertyInfo(Variant::INT,base+"button_index")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"pressed")); + + } break; + case InputEvent::SCREEN_TOUCH: { + p_list->push_back(PropertyInfo(Variant::INT,base+"finger_index")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"pressed")); + + } break; + case InputEvent::SCREEN_DRAG: { + p_list->push_back(PropertyInfo(Variant::INT,base+"finger_index")); + } break; + case InputEvent::ACTION: { + + + + if (actions==String()) { + + actions="None"; + + List<PropertyInfo> pinfo; + Globals::get_singleton()->get_property_list(&pinfo); + Vector<String> al; + + for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { + const PropertyInfo &pi=E->get(); + + if (!pi.name.begins_with("input/")) + continue; + + String name = pi.name.substr(pi.name.find("/")+1,pi.name.length()); + + + al.push_back(name); + } + + for(int i=0;i<al.size();i++) { + actions+=","; + actions+=al[i]; + } + } + + p_list->push_back(PropertyInfo(Variant::STRING,base+"action_name",PROPERTY_HINT_ENUM,actions)); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"pressed")); + + } break; + + } + } +} + +class VisualScriptNodeInstanceInputFilter : public VisualScriptNodeInstance { +public: + + VisualScriptInstance* instance; + Vector<InputEvent> filters; + + //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) { + + if (p_inputs[0]->get_type()!=Variant::INPUT_EVENT) { + r_error_str="Input value not of type event"; + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + return 0; + } + + InputEvent event = *p_inputs[0]; + + + for(int i=0;i<filters.size();i++) { + + const InputEvent &ie = filters[i]; + if (ie.type!=event.type) + continue; + + bool match=false; + + switch(ie.type) { + + case InputEvent::NONE: { + + match=true; + } break; + case InputEvent::KEY: { + + InputEventKey k = ie.key; + InputEventKey k2 = event.key; + + if (k.scancode==0 && k.unicode==0 && k2.scancode==0 && k2.unicode==0) { + match=true; + + } else { + + if ( (k.scancode!=0 && k.scancode==k2.scancode) || (k.unicode!=0 && k.unicode==k2.unicode)) { + //key valid + + if ( + k.pressed==k2.pressed && + k.echo==k2.echo && + k.mod == k2.mod + ) { + match=true; + } + } + + } + + } break; + case InputEvent::MOUSE_MOTION: { + InputEventMouseMotion mm = ie.mouse_motion; + InputEventMouseMotion mm2 = event.mouse_motion; + + if ( mm.button_mask==mm2.button_mask && + mm.mod==mm2.mod + ) { + match=true; + } + + } break; + case InputEvent::MOUSE_BUTTON: { + + InputEventMouseButton mb = ie.mouse_button; + InputEventMouseButton mb2 = event.mouse_button; + + if ( mb.button_index==mb2.button_index && + mb.pressed==mb2.pressed && + mb.doubleclick==mb2.doubleclick && + mb.mod==mb2.mod) { + match=true; + } + + + } break; + case InputEvent::JOYSTICK_MOTION: { + + InputEventJoystickMotion jm = ie.joy_motion; + InputEventJoystickMotion jm2 = event.joy_motion; + + int axis = jm.axis>>1; + + if (axis==jm2.axis) { + + if (jm.axis&1) { + //greater + if (jm2.axis_value > jm.axis_value) { + match=true; + } + } else { + //less + if (jm2.axis_value < -jm.axis_value) { + match=true; + } + } + } + + + } break; + case InputEvent::JOYSTICK_BUTTON: { + InputEventJoystickButton jb = ie.joy_button; + InputEventJoystickButton jb2 = event.joy_button; + + if ( jb.button_index==jb2.button_index && + jb.pressed == jb2.pressed + ) { + match=true; + } + } break; + case InputEvent::SCREEN_TOUCH: { + InputEventScreenTouch st = ie.screen_touch; + InputEventScreenTouch st2 = event.screen_touch; + + if ( st.index==st2.index && + st.pressed==st2.pressed) { + match=true; + } + + } break; + case InputEvent::SCREEN_DRAG: { + InputEventScreenDrag sd = ie.screen_drag; + InputEventScreenDrag sd2 = event.screen_drag; + + if (sd.index==sd2.index) { + match=true; + } + } break; + case InputEvent::ACTION: { + + InputEventAction ia = ie.action; + InputEventAction ia2 = event.action; + + if ( ia.action==ia2.action && + ia.pressed==ia2.pressed) { + match=true; + } + } break; + + } + + *p_outputs[0] = event; + + if (match) + return i; //go through match output + + } + + return STEP_NO_ADVANCE_BIT; //none found, don't advance + + + } + + +}; + + +VisualScriptNodeInstance* VisualScriptInputFilter::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceInputFilter * instance = memnew(VisualScriptNodeInstanceInputFilter ); + instance->instance=p_instance; + instance->filters=filters; + return instance; +} + + + + +VisualScriptInputFilter::VisualScriptInputFilter() { + + +} + + + + void register_visual_script_flow_control_nodes() { VisualScriptLanguage::singleton->add_register_func("flow_control/return",create_return_node<false>); @@ -414,5 +1670,9 @@ void register_visual_script_flow_control_nodes() { VisualScriptLanguage::singleton->add_register_func("flow_control/while",create_node_generic<VisualScriptWhile>); VisualScriptLanguage::singleton->add_register_func("flow_control/iterator",create_node_generic<VisualScriptIterator>); VisualScriptLanguage::singleton->add_register_func("flow_control/sequence",create_node_generic<VisualScriptSequence>); + 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>); + + } diff --git a/modules/visual_script/visual_script_flow_control.h b/modules/visual_script/visual_script_flow_control.h index 557654b080..ed0e328629 100644 --- a/modules/visual_script/visual_script_flow_control.h +++ b/modules/visual_script/visual_script_flow_control.h @@ -31,6 +31,7 @@ public: virtual String get_caption() const; virtual String get_text() const; + virtual String get_category() const { return "flow_control"; } void set_return_type(Variant::Type); Variant::Type get_return_type() const; @@ -39,7 +40,7 @@ public: bool is_return_value_enabled() const; - virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance); + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); VisualScriptReturn(); }; @@ -72,9 +73,10 @@ public: virtual String get_caption() const; virtual String get_text() const; + virtual String get_category() const { return "flow_control"; } - virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance); + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); VisualScriptCondition(); }; @@ -107,9 +109,10 @@ public: virtual String get_caption() const; virtual String get_text() const; + virtual String get_category() const { return "flow_control"; } - virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance); + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); VisualScriptWhile(); }; @@ -143,9 +146,10 @@ public: virtual String get_caption() const; virtual String get_text() const; + virtual String get_category() const { return "flow_control"; } - virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance); + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); VisualScriptIterator(); }; @@ -180,15 +184,95 @@ public: virtual String get_caption() const; virtual String get_text() const; + virtual String get_category() const { return "flow_control"; } void set_steps(int p_steps); int get_steps() const; - virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance); + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); VisualScriptSequence(); }; + + + +class VisualScriptInputSelector : public VisualScriptNode { + + OBJ_TYPE(VisualScriptInputSelector,VisualScriptNode) + + + +protected: + + static void _bind_methods(); +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "flow_control"; } + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + + VisualScriptInputSelector(); +}; + + + + +class VisualScriptInputFilter : public VisualScriptNode { + + OBJ_TYPE(VisualScriptInputFilter,VisualScriptNode) + + Vector<InputEvent> filters; + + +protected: + bool _set(const StringName& p_name, const Variant& p_value); + bool _get(const StringName& p_name,Variant &r_ret) const; + void _get_property_list( List<PropertyInfo> *p_list) const; + +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "flow_control"; } + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + + VisualScriptInputFilter(); +}; + void register_visual_script_flow_control_nodes(); diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp index 750ad00a56..4006dab4a5 100644 --- a/modules/visual_script/visual_script_func_nodes.cpp +++ b/modules/visual_script/visual_script_func_nodes.cpp @@ -485,11 +485,96 @@ void VisualScriptFunctionCall::_bind_methods() { BIND_CONSTANT( CALL_MODE_BASIC_TYPE ); } -VisualScriptNodeInstance* VisualScriptFunctionCall::instance(VScriptInstance* p_instance) { +class VisualScriptNodeInstanceFunctionCall : public VisualScriptNodeInstance { +public: - return NULL; -} + VisualScriptFunctionCall::CallMode call_mode; + NodePath node_path; + int input_args; + bool returns; + StringName function; + + VisualScriptFunctionCall *node; + 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 true; } + + 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) { + + + switch(call_mode) { + + case VisualScriptFunctionCall::CALL_MODE_SELF: { + + Object *object=instance->get_owner_ptr(); + + if (returns) { + *p_outputs[0] = object->call(function,p_inputs,input_args,r_error); + } else { + object->call(function,p_inputs,input_args,r_error); + } + } break; + case VisualScriptFunctionCall::CALL_MODE_NODE_PATH: { + + Node* node = instance->get_owner_ptr()->cast_to<Node>(); + if (!node) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Base object is not a Node!"; + return 0; + } + + Node* another = node->get_node(node_path); + if (!node) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Path does not lead Node!"; + return 0; + } + + if (returns) { + *p_outputs[0] = another->call(function,p_inputs,input_args,r_error); + } else { + another->call(function,p_inputs,input_args,r_error); + } + + } break; + case VisualScriptFunctionCall::CALL_MODE_INSTANCE: + case VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE: { + + Variant v = *p_inputs[0]; + + if (returns) { + *p_outputs[0] = v.call(function,p_inputs+1,input_args,r_error); + } else { + v.call(function,p_inputs+1,input_args,r_error); + } + + } break; + + } + return 0; + + } + + +}; + +VisualScriptNodeInstance* VisualScriptFunctionCall::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceFunctionCall * instance = memnew(VisualScriptNodeInstanceFunctionCall ); + instance->node=this; + instance->instance=p_instance; + instance->function=function; + instance->call_mode=call_mode; + instance->returns=get_output_value_port_count(); + instance->node_path=base_path; + instance->input_args = get_input_value_port_count() - ( (call_mode==CALL_MODE_BASIC_TYPE || call_mode==CALL_MODE_INSTANCE) ? 1: 0 ); + return instance; +} VisualScriptFunctionCall::VisualScriptFunctionCall() { call_mode=CALL_MODE_INSTANCE; @@ -513,6 +598,19 @@ static Ref<VisualScriptNode> create_function_call_node(const String& p_name) { ////////////////SET////////////////////// ////////////////////////////////////////// +static const char* event_type_names[InputEvent::TYPE_MAX]={ + "None", + "Key", + "MouseMotion", + "MouseButton", + "JoystickMotion", + "JoystickButton", + "ScreenTouch", + "ScreenDrag", + "Action" +}; + + int VisualScriptPropertySet::get_output_sequence_port_count() const { return 1; @@ -586,7 +684,7 @@ int VisualScriptPropertySet::get_input_value_port_count() const{ } int VisualScriptPropertySet::get_output_value_port_count() const{ - return 0; + return call_mode==CALL_MODE_BASIC_TYPE? 1 : 0; } String VisualScriptPropertySet::get_output_sequence_port_text(int p_port) const { @@ -617,9 +715,17 @@ PropertyInfo VisualScriptPropertySet::get_input_value_port_info(int p_idx) const if (call_mode==CALL_MODE_BASIC_TYPE) { - Variant::CallError ce; - Variant v = Variant::construct(basic_type,NULL,0,ce); + Variant v; + if (basic_type==Variant::INPUT_EVENT) { + InputEvent ev; + ev.type=event_type; + v=ev; + } else { + Variant::CallError ce; + v = Variant::construct(basic_type,NULL,0,ce); + } v.get_property_list(&pinfo); + } else if (call_mode==CALL_MODE_NODE_PATH) { Node *n = _get_base_node(); @@ -651,8 +757,11 @@ PropertyInfo VisualScriptPropertySet::get_input_value_port_info(int p_idx) const } PropertyInfo VisualScriptPropertySet::get_output_value_port_info(int p_idx) const{ - - return PropertyInfo(); + if (call_mode==CALL_MODE_BASIC_TYPE) { + return PropertyInfo(basic_type,"out"); + } else { + return PropertyInfo(); + } } @@ -725,6 +834,21 @@ Variant::Type VisualScriptPropertySet::get_basic_type() const{ return basic_type; } +void VisualScriptPropertySet::set_event_type(InputEvent::Type p_type) { + + if (event_type==p_type) + return; + event_type=p_type; + _change_notify(); + _update_base_type(); + ports_changed_notify(); +} + +InputEvent::Type VisualScriptPropertySet::get_event_type() const{ + + return event_type; +} + void VisualScriptPropertySet::set_base_type(const StringName& p_type) { @@ -833,6 +957,12 @@ void VisualScriptPropertySet::_validate_property(PropertyInfo& property) const { } } + if (property.name=="property/event_type") { + if (call_mode!=CALL_MODE_BASIC_TYPE || basic_type!=Variant::INPUT_EVENT) { + property.usage=0; + } + } + if (property.name=="property/node_path") { if (call_mode!=CALL_MODE_NODE_PATH) { property.usage=0; @@ -856,7 +986,14 @@ void VisualScriptPropertySet::_validate_property(PropertyInfo& property) const { if (call_mode==CALL_MODE_BASIC_TYPE) { Variant::CallError ce; - Variant v = Variant::construct(basic_type,NULL,0,ce); + Variant v; + if (basic_type==Variant::INPUT_EVENT) { + InputEvent ev; + ev.type=event_type; + v=ev; + } else { + v = Variant::construct(basic_type,NULL,0,ce); + } v.get_property_list(&pinfo); } else if (call_mode==CALL_MODE_NODE_PATH) { @@ -945,6 +1082,8 @@ void VisualScriptPropertySet::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_basic_type","basic_type"),&VisualScriptPropertySet::set_basic_type); ObjectTypeDB::bind_method(_MD("get_basic_type"),&VisualScriptPropertySet::get_basic_type); + ObjectTypeDB::bind_method(_MD("set_event_type","event_type"),&VisualScriptPropertySet::set_event_type); + ObjectTypeDB::bind_method(_MD("get_event_type"),&VisualScriptPropertySet::get_event_type); ObjectTypeDB::bind_method(_MD("set_property","property"),&VisualScriptPropertySet::set_property); ObjectTypeDB::bind_method(_MD("get_property"),&VisualScriptPropertySet::get_property); @@ -969,9 +1108,19 @@ void VisualScriptPropertySet::_bind_methods() { bt+=Variant::get_type_name(Variant::Type(i)); } + String et; + for(int i=0;i<InputEvent::TYPE_MAX;i++) { + if (i>0) + et+=","; + + et+=event_type_names[i]; + } + + ADD_PROPERTY(PropertyInfo(Variant::INT,"property/set_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance,Basic Type",PROPERTY_USAGE_NOEDITOR),_SCS("set_call_mode"),_SCS("get_call_mode")); ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type")); ADD_PROPERTY(PropertyInfo(Variant::INT,"property/basic_type",PROPERTY_HINT_ENUM,bt),_SCS("set_basic_type"),_SCS("get_basic_type")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"property/event_type",PROPERTY_HINT_ENUM,et),_SCS("set_event_type"),_SCS("get_event_type")); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"property/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_base_path"),_SCS("get_base_path")); ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/property"),_SCS("set_property"),_SCS("get_property")); ADD_PROPERTY(PropertyInfo(Variant::BOOL,"value/use_builtin"),_SCS("set_use_builtin_value"),_SCS("is_using_builtin_value")); @@ -983,9 +1132,120 @@ void VisualScriptPropertySet::_bind_methods() { } -VisualScriptNodeInstance* VisualScriptPropertySet::instance(VScriptInstance* p_instance) { +class VisualScriptNodeInstancePropertySet : public VisualScriptNodeInstance { +public: - return NULL; + + VisualScriptPropertySet::CallMode call_mode; + NodePath node_path; + StringName property; + bool use_builtin; + Variant builtin_val; + + VisualScriptPropertySet *node; + 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 true; } + + 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) { + + + switch(call_mode) { + + case VisualScriptPropertySet::CALL_MODE_SELF: { + + Object *object=instance->get_owner_ptr(); + + bool valid; + + if (use_builtin) { + object->set(property,builtin_val,&valid); + } else { + object->set(property,*p_inputs[0],&valid); + } + + if (!valid) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Invalid index property name."; + } + } break; + case VisualScriptPropertySet::CALL_MODE_NODE_PATH: { + + Node* node = instance->get_owner_ptr()->cast_to<Node>(); + if (!node) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Base object is not a Node!"; + return 0; + } + + Node* another = node->get_node(node_path); + if (!node) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Path does not lead Node!"; + return 0; + } + + bool valid; + + if (use_builtin) { + another->set(property,builtin_val,&valid); + } else { + another->set(property,*p_inputs[0],&valid); + } + + if (!valid) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Invalid index property name."; + } + + } break; + case VisualScriptPropertySet::CALL_MODE_INSTANCE: + case VisualScriptPropertySet::CALL_MODE_BASIC_TYPE: { + + Variant v = *p_inputs[0]; + + bool valid; + + if (use_builtin) { + v.set(property,builtin_val,&valid); + } else { + v.set(property,p_inputs[1],&valid); + } + + if (!valid) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Invalid index property name."; + } + + if (call_mode==VisualScriptPropertySet::CALL_MODE_BASIC_TYPE) { + *p_outputs[0]=v; + } + + } break; + + } + return 0; + + } + + +}; + +VisualScriptNodeInstance* VisualScriptPropertySet::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstancePropertySet * instance = memnew(VisualScriptNodeInstancePropertySet ); + instance->node=this; + instance->instance=p_instance; + instance->property=property; + instance->call_mode=call_mode; + instance->node_path=base_path; + instance->use_builtin=use_builtin_value; + instance->builtin_val=builtin_value; + return instance; } VisualScriptPropertySet::VisualScriptPropertySet() { @@ -993,6 +1253,7 @@ VisualScriptPropertySet::VisualScriptPropertySet() { call_mode=CALL_MODE_INSTANCE; base_type="Object"; basic_type=Variant::NIL; + event_type=InputEvent::NONE; } @@ -1012,12 +1273,12 @@ static Ref<VisualScriptNode> create_property_set_node(const String& p_name) { int VisualScriptPropertyGet::get_output_sequence_port_count() const { - return 1; + return (call_mode==CALL_MODE_SELF || call_mode==CALL_MODE_NODE_PATH)?0:1; } bool VisualScriptPropertyGet::has_input_sequence_port() const{ - return true; + return (call_mode==CALL_MODE_SELF || call_mode==CALL_MODE_NODE_PATH)?false:true; } void VisualScriptPropertyGet::_update_base_type() { //cache it because this information may not be available on load @@ -1132,8 +1393,15 @@ PropertyInfo VisualScriptPropertyGet::get_output_value_port_info(int p_idx) cons if (call_mode==CALL_MODE_BASIC_TYPE) { - Variant::CallError ce; - Variant v = Variant::construct(basic_type,NULL,0,ce); + Variant v; + if (basic_type==Variant::INPUT_EVENT) { + InputEvent ev; + ev.type=event_type; + v=ev; + } else { + Variant::CallError ce; + v = Variant::construct(basic_type,NULL,0,ce); + } v.get_property_list(&pinfo); } else if (call_mode==CALL_MODE_NODE_PATH) { @@ -1268,6 +1536,21 @@ Variant::Type VisualScriptPropertyGet::get_basic_type() const{ } +void VisualScriptPropertyGet::set_event_type(InputEvent::Type p_type) { + + if (event_type==p_type) + return; + event_type=p_type; + _change_notify(); + _update_base_type(); + ports_changed_notify(); +} + +InputEvent::Type VisualScriptPropertyGet::get_event_type() const{ + + return event_type; +} + void VisualScriptPropertyGet::_validate_property(PropertyInfo& property) const { if (property.name=="property/base_type") { @@ -1282,6 +1565,11 @@ void VisualScriptPropertyGet::_validate_property(PropertyInfo& property) const { property.usage=0; } } + if (property.name=="property/event_type") { + if (call_mode!=CALL_MODE_BASIC_TYPE || basic_type!=Variant::INPUT_EVENT) { + property.usage=0; + } + } if (property.name=="property/node_path") { if (call_mode!=CALL_MODE_NODE_PATH) { @@ -1305,7 +1593,14 @@ void VisualScriptPropertyGet::_validate_property(PropertyInfo& property) const { if (call_mode==CALL_MODE_BASIC_TYPE) { Variant::CallError ce; - Variant v = Variant::construct(basic_type,NULL,0,ce); + Variant v; + if (basic_type==Variant::INPUT_EVENT) { + InputEvent ev; + ev.type=event_type; + v=ev; + } else { + v = Variant::construct(basic_type,NULL,0,ce); + } v.get_property_list(&pinfo); } else if (call_mode==CALL_MODE_NODE_PATH) { @@ -1355,6 +1650,9 @@ void VisualScriptPropertyGet::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_basic_type","basic_type"),&VisualScriptPropertyGet::set_basic_type); ObjectTypeDB::bind_method(_MD("get_basic_type"),&VisualScriptPropertyGet::get_basic_type); + ObjectTypeDB::bind_method(_MD("set_event_type","event_type"),&VisualScriptPropertyGet::set_event_type); + ObjectTypeDB::bind_method(_MD("get_event_type"),&VisualScriptPropertyGet::get_event_type); + ObjectTypeDB::bind_method(_MD("set_property","property"),&VisualScriptPropertyGet::set_property); ObjectTypeDB::bind_method(_MD("get_property"),&VisualScriptPropertyGet::get_property); @@ -1373,10 +1671,19 @@ void VisualScriptPropertyGet::_bind_methods() { bt+=Variant::get_type_name(Variant::Type(i)); } + String et; + for(int i=0;i<InputEvent::TYPE_MAX;i++) { + if (i>0) + et+=","; + + et+=event_type_names[i]; + } + ADD_PROPERTY(PropertyInfo(Variant::INT,"property/set_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance",PROPERTY_USAGE_NOEDITOR),_SCS("set_call_mode"),_SCS("get_call_mode")); ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type")); ADD_PROPERTY(PropertyInfo(Variant::INT,"property/basic_type",PROPERTY_HINT_ENUM,bt),_SCS("set_basic_type"),_SCS("get_basic_type")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"property/event_type",PROPERTY_HINT_ENUM,et),_SCS("set_event_type"),_SCS("get_event_type")); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"property/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_base_path"),_SCS("get_base_path")); ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/property"),_SCS("set_property"),_SCS("get_property")); @@ -1385,9 +1692,107 @@ void VisualScriptPropertyGet::_bind_methods() { BIND_CONSTANT( CALL_MODE_INSTANCE); } -VisualScriptNodeInstance* VisualScriptPropertyGet::instance(VScriptInstance* p_instance) { +class VisualScriptNodeInstancePropertyGet : public VisualScriptNodeInstance { +public: - return NULL; + + VisualScriptPropertyGet::CallMode call_mode; + NodePath node_path; + StringName property; + + VisualScriptPropertyGet *node; + VisualScriptInstance *instance; + + + + //virtual int get_working_memory_size() const { return 0; } + virtual bool is_output_port_unsequenced(int p_idx) const { return (call_mode==VisualScriptPropertyGet::CALL_MODE_SELF || call_mode==VisualScriptPropertyGet::CALL_MODE_NODE_PATH); } + virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { + + //these two modes can be get directly, so they use unsequenced mode + switch(call_mode) { + + case VisualScriptPropertyGet::CALL_MODE_SELF: { + + Object *object=instance->get_owner_ptr(); + + bool valid; + + *r_value = object->get(property,&valid); + + if (!valid) { + //r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error=RTR("Invalid index property name."); + return false; + } + } break; + case VisualScriptPropertyGet::CALL_MODE_NODE_PATH: { + + Node* node = instance->get_owner_ptr()->cast_to<Node>(); + if (!node) { + //r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error=RTR("Base object is not a Node!"); + return false; + } + + Node* another = node->get_node(node_path); + if (!node) { + //r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error=RTR("Path does not lead Node!"); + return false; + } + + bool valid; + + + *r_value = another->get(property,&valid); + + if (!valid) { + //r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error=vformat(RTR("Invalid index property name '%s' in node %s."),String(property),another->get_name()); + return false; + } + + } break; + default: {}; + } + return true; + + } + + 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) { + + + bool valid; + Variant v = *p_inputs[0]; + + *p_outputs[0] = v.get(property,&valid); + + if (!valid) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str=RTR("Invalid index property name."); + + } + + + return 0; + } + + + + +}; + +VisualScriptNodeInstance* VisualScriptPropertyGet::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstancePropertyGet * instance = memnew(VisualScriptNodeInstancePropertyGet ); + instance->node=this; + instance->instance=p_instance; + instance->property=property; + instance->call_mode=call_mode; + instance->node_path=base_path; + + return instance; } VisualScriptPropertyGet::VisualScriptPropertyGet() { @@ -1395,6 +1800,7 @@ VisualScriptPropertyGet::VisualScriptPropertyGet() { call_mode=CALL_MODE_INSTANCE; base_type="Object"; basic_type=Variant::NIL; + event_type=InputEvent::NONE; } @@ -1463,7 +1869,9 @@ Node *VisualScriptScriptCall::_get_base_node() const { int VisualScriptScriptCall::get_input_value_port_count() const{ - +#if 1 + return argument_count; +#else if (call_mode==CALL_MODE_SELF) { Ref<VisualScript> vs = get_visual_script(); @@ -1501,6 +1909,7 @@ int VisualScriptScriptCall::get_input_value_port_count() const{ return 0; +#endif } int VisualScriptScriptCall::get_output_value_port_count() const{ @@ -1573,6 +1982,48 @@ String VisualScriptScriptCall::get_text() const { return " "+String(function)+"()"; } +void VisualScriptScriptCall::_update_argument_count() { + + //try to remember the amount of arguments in the function, because if loaded from scratch + //this information will not be available + + if (call_mode==CALL_MODE_SELF) { + + Ref<VisualScript> vs = get_visual_script(); + if (vs.is_valid()) { + + if (!vs->has_function(function)) + return ; + + int id = vs->get_function_node_id(function); + if (id<0) + return; + + Ref<VisualScriptFunction> func = vs->get_node(function,id); + + argument_count=func->get_argument_count(); + } + } else { + + Node*base = _get_base_node(); + if (!base) + return; + + Ref<Script> script = base->get_script(); + if (!script.is_valid()) + return ; + + List<MethodInfo> functions; + script->get_method_list(&functions); + for (List<MethodInfo>::Element *E=functions.front();E;E=E->next()) { + if (E->get().name==function) { + argument_count=E->get().arguments.size(); + return; + } + } + + } +} void VisualScriptScriptCall::set_function(const StringName& p_type){ @@ -1581,7 +2032,7 @@ void VisualScriptScriptCall::set_function(const StringName& p_type){ return; function=p_type; - + _update_argument_count(); _change_notify(); ports_changed_notify(); } @@ -1597,7 +2048,7 @@ void VisualScriptScriptCall::set_base_path(const NodePath& p_type) { return; base_path=p_type; - + _update_argument_count(); _change_notify(); ports_changed_notify(); } @@ -1614,11 +2065,25 @@ void VisualScriptScriptCall::set_call_mode(CallMode p_mode) { return; call_mode=p_mode; + _update_argument_count(); + _change_notify(); + ports_changed_notify(); +} + +void VisualScriptScriptCall::set_argument_count(int p_count) { + + argument_count=p_count; _change_notify(); ports_changed_notify(); } + +int VisualScriptScriptCall::get_argument_count() const { + + return argument_count; +} + VisualScriptScriptCall::CallMode VisualScriptScriptCall::get_call_mode() const { return call_mode; @@ -1703,24 +2168,95 @@ void VisualScriptScriptCall::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_base_path","base_path"),&VisualScriptScriptCall::set_base_path); ObjectTypeDB::bind_method(_MD("get_base_path"),&VisualScriptScriptCall::get_base_path); + ObjectTypeDB::bind_method(_MD("set_argument_count","argument_count"),&VisualScriptScriptCall::set_argument_count); + ObjectTypeDB::bind_method(_MD("get_argument_count"),&VisualScriptScriptCall::get_argument_count); ADD_PROPERTY(PropertyInfo(Variant::INT,"function/call_mode",PROPERTY_HINT_ENUM,"Self,Node Path"),_SCS("set_call_mode"),_SCS("get_call_mode")); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"function/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_base_path"),_SCS("get_base_path")); ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/function"),_SCS("set_function"),_SCS("get_function")); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/argument_count"),_SCS("set_argument_count"),_SCS("get_argument_count")); BIND_CONSTANT( CALL_MODE_SELF ); BIND_CONSTANT( CALL_MODE_NODE_PATH); } -VisualScriptNodeInstance* VisualScriptScriptCall::instance(VScriptInstance* p_instance) { +class VisualScriptNodeInstanceScriptCall : public VisualScriptNodeInstance { +public: - return NULL; + + VisualScriptScriptCall::CallMode call_mode; + NodePath node_path; + int input_args; + bool returns; + StringName function; + + VisualScriptScriptCall *node; + 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 true; } + + 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) { + + + switch(call_mode) { + + case VisualScriptScriptCall::CALL_MODE_SELF: { + + Object *object=instance->get_owner_ptr(); + + *p_outputs[0] = object->call(function,p_inputs,input_args,r_error); + + } break; + case VisualScriptScriptCall::CALL_MODE_NODE_PATH: { + + Node* node = instance->get_owner_ptr()->cast_to<Node>(); + if (!node) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Base object is not a Node!"; + return 0; + } + + Node* another = node->get_node(node_path); + if (!node) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Path does not lead Node!"; + return 0; + } + + + *p_outputs[0] = another->call(function,p_inputs,input_args,r_error); + + } break; + + } + return 0; + + } + + +}; + +VisualScriptNodeInstance* VisualScriptScriptCall::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceScriptCall * instance = memnew(VisualScriptNodeInstanceScriptCall ); + instance->node=this; + instance->instance=p_instance; + instance->function=function; + instance->call_mode=call_mode; + instance->node_path=base_path; + instance->input_args = argument_count; + return instance; } VisualScriptScriptCall::VisualScriptScriptCall() { call_mode=CALL_MODE_SELF; + argument_count=0; } @@ -1736,7 +2272,7 @@ static Ref<VisualScriptNode> create_script_call_node(const String& p_name) { ////////////////////////////////////////// -////////////////SCRIPT CALL////////////////////// +////////////////EMIT////////////////////// ////////////////////////////////////////// int VisualScriptEmitSignal::get_output_sequence_port_count() const { @@ -1865,34 +2401,111 @@ void VisualScriptEmitSignal::_bind_methods() { } -VisualScriptNodeInstance* VisualScriptEmitSignal::instance(VScriptInstance* p_instance) { +class VisualScriptNodeInstanceEmitSignal : public VisualScriptNodeInstance { +public: - return NULL; + VisualScriptEmitSignal *node; + VisualScriptInstance *instance; + int argcount; + StringName name; + + //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 true; } + + 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 = instance->get_owner_ptr(); + + obj->emit_signal(name,p_inputs,argcount); + + + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptEmitSignal::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceEmitSignal * instance = memnew(VisualScriptNodeInstanceEmitSignal ); + instance->node=this; + instance->instance=p_instance; + instance->name=name; + instance->argcount=get_input_value_port_count(); + return instance; } VisualScriptEmitSignal::VisualScriptEmitSignal() { } + + +static Ref<VisualScriptNode> create_basic_type_call_node(const String& p_name) { + + Vector<String> path = p_name.split("/"); + ERR_FAIL_COND_V(path.size()<4,Ref<VisualScriptNode>()); + String base_type = path[2]; + String method = path[3]; + + Ref<VisualScriptFunctionCall> node; + node.instance(); + + Variant::Type type=Variant::VARIANT_MAX; + + for(int i=0;i<Variant::VARIANT_MAX;i++) { + + if (Variant::get_type_name(Variant::Type(i))==base_type) { + type=Variant::Type(i); + break; + } + } + + ERR_FAIL_COND_V(type==Variant::VARIANT_MAX,Ref<VisualScriptNode>()); + + + node->set_call_mode(VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE); + node->set_basic_type(type); + node->set_function(method); + + return node; +} + + void register_visual_script_func_nodes() { - VisualScriptLanguage::singleton->add_register_func("functions/call_method/instance_call",create_function_call_node<VisualScriptFunctionCall::CALL_MODE_INSTANCE>); - VisualScriptLanguage::singleton->add_register_func("functions/call_method/basic_type_call",create_function_call_node<VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE>); - VisualScriptLanguage::singleton->add_register_func("functions/call_method/self_call",create_function_call_node<VisualScriptFunctionCall::CALL_MODE_SELF>); - VisualScriptLanguage::singleton->add_register_func("functions/call_method/node_call",create_function_call_node<VisualScriptFunctionCall::CALL_MODE_NODE_PATH>); + VisualScriptLanguage::singleton->add_register_func("functions/call_method/call_instance",create_function_call_node<VisualScriptFunctionCall::CALL_MODE_INSTANCE>); + VisualScriptLanguage::singleton->add_register_func("functions/call_method/call_basic_type",create_function_call_node<VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE>); + VisualScriptLanguage::singleton->add_register_func("functions/call_method/call_self",create_function_call_node<VisualScriptFunctionCall::CALL_MODE_SELF>); + VisualScriptLanguage::singleton->add_register_func("functions/call_method/call_node",create_function_call_node<VisualScriptFunctionCall::CALL_MODE_NODE_PATH>); - VisualScriptLanguage::singleton->add_register_func("functions/set_property/instace_set",create_property_set_node<VisualScriptPropertySet::CALL_MODE_INSTANCE>); - VisualScriptLanguage::singleton->add_register_func("functions/set_property/basic_type_set",create_property_set_node<VisualScriptPropertySet::CALL_MODE_BASIC_TYPE>); - VisualScriptLanguage::singleton->add_register_func("functions/set_property/self_set",create_property_set_node<VisualScriptPropertySet::CALL_MODE_SELF>); - VisualScriptLanguage::singleton->add_register_func("functions/set_property/node_set",create_property_set_node<VisualScriptPropertySet::CALL_MODE_NODE_PATH>); + VisualScriptLanguage::singleton->add_register_func("functions/property_set/instace_set",create_property_set_node<VisualScriptPropertySet::CALL_MODE_INSTANCE>); + VisualScriptLanguage::singleton->add_register_func("functions/property_set/basic_type_set",create_property_set_node<VisualScriptPropertySet::CALL_MODE_BASIC_TYPE>); + VisualScriptLanguage::singleton->add_register_func("functions/property_set/self_set",create_property_set_node<VisualScriptPropertySet::CALL_MODE_SELF>); + VisualScriptLanguage::singleton->add_register_func("functions/property_set/node_set",create_property_set_node<VisualScriptPropertySet::CALL_MODE_NODE_PATH>); - VisualScriptLanguage::singleton->add_register_func("functions/get_property/instance_get",create_property_get_node<VisualScriptPropertyGet::CALL_MODE_INSTANCE>); - VisualScriptLanguage::singleton->add_register_func("functions/get_property/basic_type_get",create_property_get_node<VisualScriptPropertyGet::CALL_MODE_BASIC_TYPE>); - VisualScriptLanguage::singleton->add_register_func("functions/get_property/self_get",create_property_get_node<VisualScriptPropertyGet::CALL_MODE_SELF>); - VisualScriptLanguage::singleton->add_register_func("functions/get_property/node_get",create_property_get_node<VisualScriptPropertyGet::CALL_MODE_NODE_PATH>); + VisualScriptLanguage::singleton->add_register_func("functions/property_get/instance_get",create_property_get_node<VisualScriptPropertyGet::CALL_MODE_INSTANCE>); + VisualScriptLanguage::singleton->add_register_func("functions/property_get/basic_type_get",create_property_get_node<VisualScriptPropertyGet::CALL_MODE_BASIC_TYPE>); + VisualScriptLanguage::singleton->add_register_func("functions/property_get/self_get",create_property_get_node<VisualScriptPropertyGet::CALL_MODE_SELF>); + VisualScriptLanguage::singleton->add_register_func("functions/property_get/node_get",create_property_get_node<VisualScriptPropertyGet::CALL_MODE_NODE_PATH>); - VisualScriptLanguage::singleton->add_register_func("functions/script/script_call",create_script_call_node<VisualScriptScriptCall::CALL_MODE_SELF>); - VisualScriptLanguage::singleton->add_register_func("functions/script/script_call_in_node",create_script_call_node<VisualScriptScriptCall::CALL_MODE_NODE_PATH>); - VisualScriptLanguage::singleton->add_register_func("functions/script/emit_signal",create_node_generic<VisualScriptEmitSignal>); + VisualScriptLanguage::singleton->add_register_func("functions/call_script/call_self",create_script_call_node<VisualScriptScriptCall::CALL_MODE_SELF>); + VisualScriptLanguage::singleton->add_register_func("functions/call_script/call_node",create_script_call_node<VisualScriptScriptCall::CALL_MODE_NODE_PATH>); + VisualScriptLanguage::singleton->add_register_func("functions/call_script/emit_signal",create_node_generic<VisualScriptEmitSignal>); + for(int i=0;i<Variant::VARIANT_MAX;i++) { + + Variant::Type t = Variant::Type(i); + String type_name = Variant::get_type_name(t); + Variant::CallError ce; + Variant vt = Variant::construct(t,NULL,0,ce); + List<MethodInfo> ml; + vt.get_method_list(&ml); + + for (List<MethodInfo>::Element *E=ml.front();E;E=E->next()) { + VisualScriptLanguage::singleton->add_register_func("functions/by_type/"+type_name+"/"+E->get().name,create_basic_type_call_node); + } + } } diff --git a/modules/visual_script/visual_script_func_nodes.h b/modules/visual_script/visual_script_func_nodes.h index 940a133d63..2ccc61242a 100644 --- a/modules/visual_script/visual_script_func_nodes.h +++ b/modules/visual_script/visual_script_func_nodes.h @@ -50,6 +50,7 @@ public: virtual String get_caption() const; virtual String get_text() const; + virtual String get_category() const { return "functions"; } void set_basic_type(Variant::Type p_type); Variant::Type get_basic_type() const; @@ -69,7 +70,7 @@ public: void set_use_default_args(int p_amount); int get_use_default_args() const; - virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance); + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); VisualScriptFunctionCall(); }; @@ -92,12 +93,13 @@ public: private: CallMode call_mode; - Variant::Type basic_type; + Variant::Type basic_type; StringName base_type; NodePath base_path; StringName property; bool use_builtin_value; Variant builtin_value; + InputEvent::Type event_type; Node *_get_base_node() const; StringName _get_base_type() const; @@ -127,6 +129,7 @@ public: virtual String get_caption() const; virtual String get_text() const; + virtual String get_category() const { return "functions"; } void set_base_type(const StringName& p_type); StringName get_base_type() const; @@ -134,6 +137,9 @@ public: void set_basic_type(Variant::Type p_type); Variant::Type get_basic_type() const; + void set_event_type(InputEvent::Type p_type); + InputEvent::Type get_event_type() const; + void set_property(const StringName& p_type); StringName get_property() const; @@ -149,7 +155,7 @@ public: void set_builtin_value(const Variant &p_value); Variant get_builtin_value() const; - virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance); + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); VisualScriptPropertySet(); }; @@ -175,6 +181,7 @@ private: StringName base_type; NodePath base_path; StringName property; + InputEvent::Type event_type; void _update_base_type(); Node *_get_base_node() const; @@ -204,6 +211,7 @@ public: virtual String get_caption() const; virtual String get_text() const; + virtual String get_category() const { return "functions"; } void set_base_type(const StringName& p_type); StringName get_base_type() const; @@ -211,6 +219,9 @@ public: void set_basic_type(Variant::Type p_type); Variant::Type get_basic_type() const; + void set_event_type(InputEvent::Type p_type); + InputEvent::Type get_event_type() const; + void set_property(const StringName& p_type); StringName get_property() const; @@ -220,7 +231,7 @@ public: void set_call_mode(CallMode p_mode); CallMode get_call_mode() const; - virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance); + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); VisualScriptPropertyGet(); }; @@ -246,11 +257,13 @@ private: CallMode call_mode; NodePath base_path; StringName function; + int argument_count; Node *_get_base_node() const; + void _update_argument_count(); protected: virtual void _validate_property(PropertyInfo& property) const; @@ -274,6 +287,7 @@ public: virtual String get_caption() const; virtual String get_text() const; + virtual String get_category() const { return "functions"; } void set_function(const StringName& p_type); StringName get_function() const; @@ -284,9 +298,11 @@ public: void set_call_mode(CallMode p_mode); CallMode get_call_mode() const; + void set_argument_count(int p_count); + int get_argument_count() const; - virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance); + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); VisualScriptScriptCall(); }; @@ -328,11 +344,12 @@ public: virtual String get_caption() const; virtual String get_text() const; + virtual String get_category() const { return "functions"; } void set_signal(const StringName& p_type); StringName get_signal() const; - virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance); + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); VisualScriptEmitSignal(); }; diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp index 1e898675d3..d205a40f76 100644 --- a/modules/visual_script/visual_script_nodes.cpp +++ b/modules/visual_script/visual_script_nodes.cpp @@ -53,7 +53,15 @@ bool VisualScriptFunction::_set(const StringName& p_name, const Variant& p_valu } + if (p_name=="stack/stackless") { + set_stack_less(p_value); + return true; + } + if (p_name=="stack/size") { + stack_size=p_value; + return true; + } return false; } @@ -81,6 +89,16 @@ bool VisualScriptFunction::_get(const StringName& p_name,Variant &r_ret) const } + if (p_name=="stack/stackless") { + r_ret=stack_less; + return true; + } + + if (p_name=="stack/size") { + r_ret=stack_size; + return true; + } + return false; } void VisualScriptFunction::_get_property_list( List<PropertyInfo> *p_list) const { @@ -96,6 +114,11 @@ void VisualScriptFunction::_get_property_list( List<PropertyInfo> *p_list) cons p_list->push_back(PropertyInfo(Variant::INT,"argument/"+itos(i+1)+"/type",PROPERTY_HINT_ENUM,argt)); p_list->push_back(PropertyInfo(Variant::STRING,"argument/"+itos(i+1)+"/name")); } + if (!stack_less) { + p_list->push_back(PropertyInfo(Variant::INT,"stack/size",PROPERTY_HINT_RANGE,"1,100000")); + } + p_list->push_back(PropertyInfo(Variant::BOOL,"stack/stackless")); + } @@ -201,15 +224,75 @@ int VisualScriptFunction::get_argument_count() const { return arguments.size(); } +class VisualScriptNodeInstanceFunction : public VisualScriptNodeInstance { +public: -VisualScriptNodeInstance* VisualScriptFunction::instance(VScriptInstance* p_instance) { + VisualScriptFunction *node; + VisualScriptInstance *instance; - return NULL; + //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 true; } + + 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) { + + int ac = node->get_argument_count(); + + for(int i=0;i<ac;i++) { +#ifdef DEBUG_ENABLED + Variant::Type expected = node->get_argument_type(i); + if (expected!=Variant::NIL) { + if (!Variant::can_convert_strict(p_inputs[i]->get_type(),expected)) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.expected=expected; + r_error.argument=i; + return 0; + } + } +#endif + + *p_outputs[i]=*p_inputs[i]; + } + + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptFunction::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceFunction * instance = memnew(VisualScriptNodeInstanceFunction ); + instance->node=this; + instance->instance=p_instance; + return instance; } VisualScriptFunction::VisualScriptFunction() { + stack_size=256; + stack_less=false; +} + + +void VisualScriptFunction::set_stack_less(bool p_enable) { + stack_less=p_enable; + _change_notify(); +} + +bool VisualScriptFunction::is_stack_less() const { + return stack_less; +} + +void VisualScriptFunction::set_stack_size(int p_size) { + + ERR_FAIL_COND(p_size <1 || p_size>100000); + stack_size=p_size; +} + +int VisualScriptFunction::get_stack_size() const { + return stack_size; } @@ -425,9 +508,51 @@ void VisualScriptOperator::_bind_methods() { } -VisualScriptNodeInstance* VisualScriptOperator::instance(VScriptInstance* p_instance) { +class VisualScriptNodeInstanceOperator : public VisualScriptNodeInstance { +public: - return NULL; + bool unary; + Variant::Operator op; + + //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 true; } + + 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) { + + bool valid; + if (unary) { + + Variant::evaluate(op,*p_inputs[0],Variant(),*p_outputs[0],valid); + } else { + Variant::evaluate(op,*p_inputs[0],*p_inputs[1],*p_outputs[0],valid); + } + + 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()); + } + } + + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptOperator::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceOperator * instance = memnew(VisualScriptNodeInstanceOperator ); + instance->unary=get_input_value_port_count()==1; + instance->op=op; + return instance; } VisualScriptOperator::VisualScriptOperator() { @@ -447,37 +572,42 @@ static Ref<VisualScriptNode> create_op_node(const String& p_name) { } ////////////////////////////////////////// -////////////////VARIABLE////////////////// +////////////////VARIABLE GET////////////////// ////////////////////////////////////////// -int VisualScriptVariable::get_output_sequence_port_count() const { +int VisualScriptVariableGet::get_output_sequence_port_count() const { - return 1; + return 0; } -bool VisualScriptVariable::has_input_sequence_port() const{ +bool VisualScriptVariableGet::has_input_sequence_port() const{ - return true; + return false; } -int VisualScriptVariable::get_input_value_port_count() const{ +int VisualScriptVariableGet::get_input_value_port_count() const{ - return 1; + return 0; } -int VisualScriptVariable::get_output_value_port_count() const{ +int VisualScriptVariableGet::get_output_value_port_count() const{ return 1; } -String VisualScriptVariable::get_output_sequence_port_text(int p_port) const { +String VisualScriptVariableGet::get_output_sequence_port_text(int p_port) const { return String(); } -PropertyInfo VisualScriptVariable::get_input_value_port_info(int p_idx) const{ +PropertyInfo VisualScriptVariableGet::get_input_value_port_info(int p_idx) const{ + + return PropertyInfo(); +} + +PropertyInfo VisualScriptVariableGet::get_output_value_port_info(int p_idx) const{ PropertyInfo pinfo; - pinfo.name="set"; + pinfo.name="value"; if (get_visual_script().is_valid() && get_visual_script()->has_variable(variable)) { PropertyInfo vinfo = get_visual_script()->get_variable_info(variable); pinfo.type=vinfo.type; @@ -487,10 +617,134 @@ PropertyInfo VisualScriptVariable::get_input_value_port_info(int p_idx) const{ return pinfo; } -PropertyInfo VisualScriptVariable::get_output_value_port_info(int p_idx) const{ + +String VisualScriptVariableGet::get_caption() const { + + return "Variable"; +} + +String VisualScriptVariableGet::get_text() const { + + return variable; +} + +void VisualScriptVariableGet::set_variable(StringName p_variable) { + + if (variable==p_variable) + return; + variable=p_variable; + ports_changed_notify(); + +} + +StringName VisualScriptVariableGet::get_variable() const{ + + return variable; +} + +void VisualScriptVariableGet::_validate_property(PropertyInfo& property) const { + + if (property.name=="variable/name" && get_visual_script().is_valid()) { + Ref<VisualScript> vs = get_visual_script(); + List<StringName> vars; + vs->get_variable_list(&vars); + + String vhint; + for (List<StringName>::Element *E=vars.front();E;E=E->next()) { + if (vhint!=String()) + vhint+=","; + + vhint+=E->get().operator String(); + } + + property.hint=PROPERTY_HINT_ENUM; + property.hint_string=vhint; + } +} + +void VisualScriptVariableGet::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_variable","name"),&VisualScriptVariableGet::set_variable); + ObjectTypeDB::bind_method(_MD("get_variable"),&VisualScriptVariableGet::get_variable); + + + ADD_PROPERTY(PropertyInfo(Variant::STRING,"variable/name"),_SCS("set_variable"),_SCS("get_variable")); + +} + +class VisualScriptNodeInstanceVariableGet : public VisualScriptNodeInstance { +public: + + VisualScriptVariableGet *node; + VisualScriptInstance *instance; + StringName variable; + + //virtual int get_working_memory_size() const { return 0; } + virtual bool is_output_port_unsequenced(int p_idx) const { return true; } + virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { + + if (instance->get_variable(variable,r_value)==false) { + r_error=RTR("VariableGet not found in script: ")+"'"+String(variable)+"'"; + return false; + } else { + return true; + } + } + + 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* VisualScriptVariableGet::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceVariableGet * instance = memnew(VisualScriptNodeInstanceVariableGet ); + instance->node=this; + instance->instance=p_instance; + instance->variable=variable; + return instance; +} +VisualScriptVariableGet::VisualScriptVariableGet() { + + +} + + +////////////////////////////////////////// +////////////////VARIABLE GET////////////////// +////////////////////////////////////////// + +int VisualScriptVariableSet::get_output_sequence_port_count() const { + + return 1; +} + +bool VisualScriptVariableSet::has_input_sequence_port() const{ + + return true; +} + +int VisualScriptVariableSet::get_input_value_port_count() const{ + + return 1; +} +int VisualScriptVariableSet::get_output_value_port_count() const{ + + return 0; +} + +String VisualScriptVariableSet::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptVariableSet::get_input_value_port_info(int p_idx) const{ PropertyInfo pinfo; - pinfo.name="get"; + pinfo.name="set"; if (get_visual_script().is_valid() && get_visual_script()->has_variable(variable)) { PropertyInfo vinfo = get_visual_script()->get_variable_info(variable); pinfo.type=vinfo.type; @@ -500,18 +754,23 @@ PropertyInfo VisualScriptVariable::get_output_value_port_info(int p_idx) const{ return pinfo; } +PropertyInfo VisualScriptVariableSet::get_output_value_port_info(int p_idx) const{ -String VisualScriptVariable::get_caption() const { + return PropertyInfo(); +} - return "Variable"; + +String VisualScriptVariableSet::get_caption() const { + + return "VariableSet"; } -String VisualScriptVariable::get_text() const { +String VisualScriptVariableSet::get_text() const { return variable; } -void VisualScriptVariable::set_variable(StringName p_variable) { +void VisualScriptVariableSet::set_variable(StringName p_variable) { if (variable==p_variable) return; @@ -520,12 +779,12 @@ void VisualScriptVariable::set_variable(StringName p_variable) { } -StringName VisualScriptVariable::get_variable() const{ +StringName VisualScriptVariableSet::get_variable() const{ return variable; } -void VisualScriptVariable::_validate_property(PropertyInfo& property) const { +void VisualScriptVariableSet::_validate_property(PropertyInfo& property) const { if (property.name=="variable/name" && get_visual_script().is_valid()) { Ref<VisualScript> vs = get_visual_script(); @@ -545,22 +804,50 @@ void VisualScriptVariable::_validate_property(PropertyInfo& property) const { } } -void VisualScriptVariable::_bind_methods() { +void VisualScriptVariableSet::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_variable","name"),&VisualScriptVariable::set_variable); - ObjectTypeDB::bind_method(_MD("get_variable"),&VisualScriptVariable::get_variable); + ObjectTypeDB::bind_method(_MD("set_variable","name"),&VisualScriptVariableSet::set_variable); + ObjectTypeDB::bind_method(_MD("get_variable"),&VisualScriptVariableSet::get_variable); ADD_PROPERTY(PropertyInfo(Variant::STRING,"variable/name"),_SCS("set_variable"),_SCS("get_variable")); } -VisualScriptNodeInstance* VisualScriptVariable::instance(VScriptInstance* p_instance) { +class VisualScriptNodeInstanceVariableSet : public VisualScriptNodeInstance { +public: - return NULL; -} + VisualScriptVariableSet *node; + VisualScriptInstance *instance; + StringName variable; + + //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) { + + if (instance->set_variable(variable,*p_inputs[0])==false) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD ; + r_error_str=RTR("VariableSet not found in script: ")+"'"+String(variable)+"'"; + } -VisualScriptVariable::VisualScriptVariable() { + + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptVariableSet::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceVariableSet * instance = memnew(VisualScriptNodeInstanceVariableSet ); + instance->node=this; + instance->instance=p_instance; + instance->variable=variable; + return instance; +} +VisualScriptVariableSet::VisualScriptVariableSet() { } @@ -679,9 +966,33 @@ void VisualScriptConstant::_bind_methods() { } -VisualScriptNodeInstance* VisualScriptConstant::instance(VScriptInstance* p_instance) { +class VisualScriptNodeInstanceConstant : public VisualScriptNodeInstance { +public: - return NULL; + Variant constant; + //virtual int get_working_memory_size() const { return 0; } + virtual bool is_output_port_unsequenced(int p_idx) const { return true; } + virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { + + *r_value=constant; + + return true; + + } + + 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* VisualScriptConstant::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceConstant * instance = memnew(VisualScriptNodeInstanceConstant ); + instance->constant=value; + return instance; } VisualScriptConstant::VisualScriptConstant() { @@ -747,11 +1058,34 @@ String VisualScriptIndexGet::get_text() const { } -VisualScriptNodeInstance* VisualScriptIndexGet::instance(VScriptInstance* p_instance) { +class VisualScriptNodeInstanceIndexGet : public VisualScriptNodeInstance { +public: - return NULL; -} + //virtual int get_working_memory_size() const { return 0; } + //virtual bool is_output_port_unsequenced(int p_idx) const { return true; } + //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) { + + bool valid; + *p_outputs[0] = p_inputs[0]->get(*p_inputs[1],&valid); + + if (!valid) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Invalid get: "+p_inputs[0]->get_construct_string(); + } + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptIndexGet::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceIndexGet * instance = memnew(VisualScriptNodeInstanceIndexGet ); + return instance; +} VisualScriptIndexGet::VisualScriptIndexGet() { @@ -816,11 +1150,35 @@ String VisualScriptIndexSet::get_text() const { } -VisualScriptNodeInstance* VisualScriptIndexSet::instance(VScriptInstance* p_instance) { +class VisualScriptNodeInstanceIndexSet : public VisualScriptNodeInstance { +public: - return NULL; -} + //virtual int get_working_memory_size() const { return 0; } + //virtual bool is_output_port_unsequenced(int p_idx) const { return true; } + //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) { + + bool valid; + *p_outputs[0]=*p_inputs[0]; + p_outputs[0]->set(*p_inputs[1],*p_inputs[2],&valid); + + if (!valid) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Invalid set: "+p_inputs[1]->get_construct_string(); + } + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptIndexSet::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceIndexSet * instance = memnew(VisualScriptNodeInstanceIndexSet ); + return instance; +} VisualScriptIndexSet::VisualScriptIndexSet() { @@ -889,10 +1247,33 @@ int VisualScriptGlobalConstant::get_global_constant() { } +class VisualScriptNodeInstanceGlobalConstant : public VisualScriptNodeInstance { +public: -VisualScriptNodeInstance* VisualScriptGlobalConstant::instance(VScriptInstance* p_instance) { + int index; + //virtual int get_working_memory_size() const { return 0; } + virtual bool is_output_port_unsequenced(int p_idx) const { return true; } + virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { - return NULL; + *r_value = GlobalConstants::get_global_constant_value(index); + return true; + + } + + 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* VisualScriptGlobalConstant::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceGlobalConstant * instance = memnew(VisualScriptNodeInstanceGlobalConstant ); + instance->index=index; + return instance; } void VisualScriptGlobalConstant::_bind_methods() { @@ -931,6 +1312,17 @@ const char* VisualScriptMathConstant::const_name[MATH_CONSTANT_MAX]={ "E", "Sqrt2", }; + +double VisualScriptMathConstant::const_value[MATH_CONSTANT_MAX]={ + 1.0, + Math_PI, + Math_PI*2, + Math_PI*0.5, + 2.71828182845904523536, + Math::sqrt(2.0) +}; + + int VisualScriptMathConstant::get_output_sequence_port_count() const { return 0; @@ -962,7 +1354,7 @@ PropertyInfo VisualScriptMathConstant::get_input_value_port_info(int p_idx) cons PropertyInfo VisualScriptMathConstant::get_output_value_port_info(int p_idx) const{ - return PropertyInfo(Variant::INT,"value"); + return PropertyInfo(Variant::REAL,"value"); } @@ -987,13 +1379,36 @@ VisualScriptMathConstant::MathConstant VisualScriptMathConstant::get_math_consta return constant; } +class VisualScriptNodeInstanceMathConstant : public VisualScriptNodeInstance { +public: + float value; + //virtual int get_working_memory_size() const { return 0; } + virtual bool is_output_port_unsequenced(int p_idx) const { return true; } + virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { -VisualScriptNodeInstance* VisualScriptMathConstant::instance(VScriptInstance* p_instance) { + *r_value = value; + return true; - return NULL; + } + + 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* VisualScriptMathConstant::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceMathConstant * instance = memnew(VisualScriptNodeInstanceMathConstant ); + instance->value=const_value[constant]; + return instance; } + void VisualScriptMathConstant::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_math_constant","which"),&VisualScriptMathConstant::set_math_constant); @@ -1080,11 +1495,35 @@ String VisualScriptEngineSingleton::get_singleton() { -VisualScriptNodeInstance* VisualScriptEngineSingleton::instance(VScriptInstance* p_instance) { +class VisualScriptNodeInstanceEngineSingleton : public VisualScriptNodeInstance { +public: - return NULL; + Object* singleton; + + //virtual int get_working_memory_size() const { return 0; } + virtual bool is_output_port_unsequenced(int p_idx) const { return true; } + virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { + + *r_value=singleton; + return true; + } + + 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* VisualScriptEngineSingleton::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceEngineSingleton * instance = memnew(VisualScriptNodeInstanceEngineSingleton ); + instance->singleton=Globals::get_singleton()->get_singleton_object(singleton); + return instance; } + void VisualScriptEngineSingleton::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_singleton","name"),&VisualScriptEngineSingleton::set_singleton); @@ -1176,12 +1615,53 @@ NodePath VisualScriptSceneNode::get_node_path() { } +class VisualScriptNodeInstanceSceneNode : public VisualScriptNodeInstance { +public: -VisualScriptNodeInstance* VisualScriptSceneNode::instance(VScriptInstance* p_instance) { + VisualScriptSceneNode *node; + VisualScriptInstance *instance; + NodePath path; - return NULL; + //virtual int get_working_memory_size() const { return 0; } + virtual bool is_output_port_unsequenced(int p_idx) const { return true; } + virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { + + Node* node = instance->get_owner_ptr()->cast_to<Node>(); + if (!node) { + r_error="Base object is not a Node!"; + return false; + } + + + + Node* another = node->get_node(path); + if (!node) { + r_error="Path does not lead Node!"; + return false; + } + + *r_value=another; + return true; + } + + 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* VisualScriptSceneNode::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceSceneNode * instance = memnew(VisualScriptNodeInstanceSceneNode ); + instance->node=this; + instance->instance=p_instance; + instance->path=path; + return instance; } + #ifdef TOOLS_ENABLED static Node* _find_script_node(Node* p_edited_scene,Node* p_current_node,const Ref<Script> &script) { @@ -1302,12 +1782,51 @@ String VisualScriptSceneTree::get_text() const { } +class VisualScriptNodeInstanceSceneTree : public VisualScriptNodeInstance { +public: -VisualScriptNodeInstance* VisualScriptSceneTree::instance(VScriptInstance* p_instance) { + VisualScriptSceneTree *node; + VisualScriptInstance *instance; - return NULL; + //virtual int get_working_memory_size() const { return 0; } + virtual bool is_output_port_unsequenced(int p_idx) const { return true; } + virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { + + Node* node = instance->get_owner_ptr()->cast_to<Node>(); + if (!node) { + r_error="Base object is not a Node!"; + return false; + } + + SceneTree* tree = node->get_tree(); + if (!tree) { + r_error="Attempt to get SceneTree while node is not in the active tree."; + return false; + } + + *r_value=tree; + return true; + + } + + 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* VisualScriptSceneTree::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceSceneTree * instance = memnew(VisualScriptNodeInstanceSceneTree ); + instance->node=this; + instance->instance=p_instance; + return instance; } + void VisualScriptSceneTree::_validate_property(PropertyInfo& property) const { } @@ -1382,10 +1901,31 @@ String VisualScriptResourcePath::get_resource_path() { } +class VisualScriptNodeInstanceResourcePath : public VisualScriptNodeInstance { +public: -VisualScriptNodeInstance* VisualScriptResourcePath::instance(VScriptInstance* p_instance) { + String path; - return NULL; + //virtual int get_working_memory_size() const { return 0; } + virtual bool is_output_port_unsequenced(int p_idx) const { return true; } + virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { + *r_value = path; + return true; + } + + 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* VisualScriptResourcePath::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceResourcePath * instance = memnew(VisualScriptNodeInstanceResourcePath ); + instance->path=path; + return instance; } @@ -1404,9 +1944,499 @@ VisualScriptResourcePath::VisualScriptResourcePath() { } + +////////////////////////////////////////// +////////////////SELF/////////// +////////////////////////////////////////// + +int VisualScriptSelf::get_output_sequence_port_count() const { + + return 0; +} + +bool VisualScriptSelf::has_input_sequence_port() const{ + + return false; +} + +int VisualScriptSelf::get_input_value_port_count() const{ + + return 0; +} +int VisualScriptSelf::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptSelf::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptSelf::get_input_value_port_info(int p_idx) const{ + + return PropertyInfo(); +} + +PropertyInfo VisualScriptSelf::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(Variant::OBJECT,"instance"); +} + + +String VisualScriptSelf::get_caption() const { + + return "Self"; +} + +String VisualScriptSelf::get_text() const { + + if (get_visual_script().is_valid()) + return get_visual_script()->get_instance_base_type(); + else + return ""; +} + + +class VisualScriptNodeInstanceSelf : 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 true; } + virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { + + *r_value = instance->get_owner_ptr(); + return true; + } + + 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* VisualScriptSelf::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceSelf * instance = memnew(VisualScriptNodeInstanceSelf ); + instance->instance=p_instance; + return instance; +} + + + +void VisualScriptSelf::_bind_methods() { + +} + +VisualScriptSelf::VisualScriptSelf() { + + +} + +////////////////////////////////////////// +////////////////CUSTOM (SCRIPTED)/////////// +////////////////////////////////////////// + +int VisualScriptCustomNode::get_output_sequence_port_count() const { + + if (get_script_instance() && get_script_instance()->has_method("_get_output_sequence_port_count")) { + return get_script_instance()->call("_get_output_sequence_port_count"); + } + return 0; +} + +bool VisualScriptCustomNode::has_input_sequence_port() const{ + + if (get_script_instance() && get_script_instance()->has_method("_has_input_sequence_port")) { + return get_script_instance()->call("_has_input_sequence_port"); + } + return false; +} + +int VisualScriptCustomNode::get_input_value_port_count() const{ + + if (get_script_instance() && get_script_instance()->has_method("_get_input_value_port_count")) { + return get_script_instance()->call("_get_input_value_port_count"); + } + return 0; +} +int VisualScriptCustomNode::get_output_value_port_count() const{ + + if (get_script_instance() && get_script_instance()->has_method("_get_output_value_port_count")) { + return get_script_instance()->call("_get_output_value_port_count"); + } + return 0; +} + +String VisualScriptCustomNode::get_output_sequence_port_text(int p_port) const { + + if (get_script_instance() && get_script_instance()->has_method("_get_output_sequence_port_text")) { + return get_script_instance()->call("_get_output_sequence_port_text",p_port); + } + + return String(); +} + +PropertyInfo VisualScriptCustomNode::get_input_value_port_info(int p_idx) const{ + + PropertyInfo info; + if (get_script_instance() && get_script_instance()->has_method("_get_input_value_port_type")) { + info.type=Variant::Type(int(get_script_instance()->call("_get_input_value_port_type",p_idx))); + } + if (get_script_instance() && get_script_instance()->has_method("_get_input_value_port_name")) { + info.name=get_script_instance()->call("_get_input_value_port_name",p_idx); + } + return info; +} + +PropertyInfo VisualScriptCustomNode::get_output_value_port_info(int p_idx) const{ + + PropertyInfo info; + if (get_script_instance() && get_script_instance()->has_method("_get_output_value_port_type")) { + info.type=Variant::Type(int(get_script_instance()->call("_get_output_value_port_type",p_idx))); + } + if (get_script_instance() && get_script_instance()->has_method("_get_output_value_port_name")) { + info.name=get_script_instance()->call("_get_output_value_port_name",p_idx); + } + return info; +} + + +String VisualScriptCustomNode::get_caption() const { + + if (get_script_instance() && get_script_instance()->has_method("_get_caption")) { + return get_script_instance()->call("_get_caption"); + } + return "CustomNode"; +} + +String VisualScriptCustomNode::get_text() const { + + if (get_script_instance() && get_script_instance()->has_method("_get_text")) { + return get_script_instance()->call("_get_text"); + } + return ""; +} + +String VisualScriptCustomNode::get_category() const { + + if (get_script_instance() && get_script_instance()->has_method("_get_category")) { + return get_script_instance()->call("_get_category"); + } + return "custom"; +} + +class VisualScriptNodeInstanceCustomNode : public VisualScriptNodeInstance { +public: + + VisualScriptInstance* instance; + VisualScriptCustomNode *node; + int in_count; + int out_count; + int work_mem_size; + Vector<bool> out_unsequenced; + + virtual int get_working_memory_size() const { return work_mem_size; } + virtual bool is_output_port_unsequenced(int p_idx) const { return out_unsequenced[p_idx]; } + virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { + + if (!node->get_script_instance() || !node->get_script_instance()->has_method(VisualScriptLanguage::singleton->_get_output_port_unsequenced)) { +#ifdef DEBUG_ENABLED + r_error=RTR("Custom node has no _get_output_port_unsequenced(idx,wmem), but unsequenced ports were specified."); + return false; + } +#endif + + Array work_mem(true); + work_mem.resize(work_mem_size); + + *r_value = node->get_script_instance()->call(VisualScriptLanguage::singleton->_get_output_port_unsequenced,p_idx,work_mem); + + + for(int i=0;i<work_mem_size;i++) { + if (i<work_mem.size()) { + p_working_mem[i]=work_mem[i]; + } + } + + return true; + + } + + 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) { + + if (node->get_script_instance()) { +#ifdef DEBUG_ENABLED + if (!node->get_script_instance()->has_method(VisualScriptLanguage::singleton->_step)) { + r_error_str=RTR("Custom node has no _step() method, can't process graph."); + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + return 0; + } +#endif + Array in_values(true); + Array out_values(true); + Array work_mem(true); + + in_values.resize(in_count); + + for(int i=0;i<in_count;i++) { + in_values[i]=p_inputs[i]; + } + + out_values.resize(in_count); + + work_mem.resize(work_mem_size); + + for(int i=0;i<work_mem_size;i++) { + work_mem[i]=p_working_mem[i]; + } + + int ret_out; + + Variant ret = node->get_script_instance()->call(VisualScriptLanguage::singleton->_step,in_values,out_values,p_start_mode,work_mem); + if (ret.get_type()==Variant::STRING) { + r_error_str=ret; + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + return 0; + } else if (ret.is_num()) { + ret_out=ret; + } else { + r_error_str=RTR("Invalid return value from _step(), must be integer (seq out), or string (error)."); + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + return 0; + } + + for(int i=0;i<out_count;i++) { + if (i<out_values.size()) { + *p_outputs[i]=out_values[i]; + } + } + + for(int i=0;i<work_mem_size;i++) { + if (i<work_mem.size()) { + p_working_mem[i]=work_mem[i]; + } + } + + return ret_out; + + } + + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptCustomNode::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceCustomNode * instance = memnew(VisualScriptNodeInstanceCustomNode ); + instance->instance=p_instance; + instance->in_count=get_input_value_port_count(); + instance->out_count=get_output_value_port_count(); + + for(int i=0;i<instance->out_count;i++) { + bool unseq = get_script_instance() && get_script_instance()->has_method("_is_output_port_unsequenced") && bool(get_script_instance()->call("_is_output_port_unsequenced",i)); + instance->out_unsequenced.push_back(unseq); + } + + if (get_script_instance() && get_script_instance()->has_method("_get_working_memory_size")) { + instance->work_mem_size = get_script_instance()->call("_get_working_memory_size"); + } else { + instance->work_mem_size=0; + } + + return instance; +} + + + +void VisualScriptCustomNode::_bind_methods() { + + BIND_VMETHOD( MethodInfo(Variant::INT,"_get_output_sequence_port_count") ); + BIND_VMETHOD( MethodInfo(Variant::BOOL,"_has_input_sequence_port") ); + + BIND_VMETHOD( MethodInfo(Variant::STRING,"_get_output_sequence_port_text",PropertyInfo(Variant::INT,"idx")) ); + BIND_VMETHOD( MethodInfo(Variant::INT,"_get_input_value_port_count") ); + BIND_VMETHOD( MethodInfo(Variant::INT,"_get_output_value_port_count") ); + + BIND_VMETHOD( MethodInfo(Variant::INT,"_get_input_value_port_type",PropertyInfo(Variant::INT,"idx")) ); + BIND_VMETHOD( MethodInfo(Variant::STRING,"_get_input_value_port_name",PropertyInfo(Variant::INT,"idx")) ); + + BIND_VMETHOD( MethodInfo(Variant::INT,"_get_output_value_port_type",PropertyInfo(Variant::INT,"idx")) ); + BIND_VMETHOD( MethodInfo(Variant::STRING,"_get_output_value_port_name",PropertyInfo(Variant::INT,"idx")) ); + + BIND_VMETHOD( MethodInfo(Variant::STRING,"_get_caption") ); + BIND_VMETHOD( MethodInfo(Variant::STRING,"_get_text") ); + BIND_VMETHOD( MethodInfo(Variant::STRING,"_get_category") ); + + BIND_VMETHOD( MethodInfo(Variant::INT,"_get_working_memory_size") ); + BIND_VMETHOD( MethodInfo(Variant::INT,"_is_output_port_unsequenced",PropertyInfo(Variant::INT,"idx")) ); + BIND_VMETHOD( MethodInfo(Variant::INT,"_get_output_port_unsequenced",PropertyInfo(Variant::INT,"idx"),PropertyInfo(Variant::ARRAY,"work_mem")) ); + BIND_VMETHOD( MethodInfo(Variant::NIL,"_step:Variant",PropertyInfo(Variant::ARRAY,"inputs"),PropertyInfo(Variant::ARRAY,"outputs"),PropertyInfo(Variant::INT,"start_mode"),PropertyInfo(Variant::ARRAY,"working_mem")) ); + + BIND_CONSTANT( START_MODE_BEGIN_SEQUENCE ); + BIND_CONSTANT( START_MODE_CONTINUE_SEQUENCE ); + BIND_CONSTANT( START_MODE_RESUME_YIELD ); + + BIND_CONSTANT( STEP_PUSH_STACK_BIT ); + BIND_CONSTANT( STEP_GO_BACK_BIT ); + BIND_CONSTANT( STEP_NO_ADVANCE_BIT ); + BIND_CONSTANT( STEP_EXIT_FUNCTION_BIT ); + BIND_CONSTANT( STEP_YIELD_BIT ); + +} + +VisualScriptCustomNode::VisualScriptCustomNode() { + + +} + +////////////////////////////////////////// +////////////////SUBCALL/////////// +////////////////////////////////////////// + +int VisualScriptSubCall::get_output_sequence_port_count() const { + + return 1; +} + +bool VisualScriptSubCall::has_input_sequence_port() const{ + + return true; +} + +int VisualScriptSubCall::get_input_value_port_count() const{ + + Ref<Script> script = get_script(); + + if (script.is_valid() && script->has_method(VisualScriptLanguage::singleton->_subcall)) { + + MethodInfo mi = script->get_method_info(VisualScriptLanguage::singleton->_subcall); + return mi.arguments.size(); + } + + return 0; +} +int VisualScriptSubCall::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptSubCall::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptSubCall::get_input_value_port_info(int p_idx) const{ + + Ref<Script> script = get_script(); + if (script.is_valid() && script->has_method(VisualScriptLanguage::singleton->_subcall)) { + + MethodInfo mi = script->get_method_info(VisualScriptLanguage::singleton->_subcall); + return mi.arguments[p_idx]; + } + + return PropertyInfo(); +} + +PropertyInfo VisualScriptSubCall::get_output_value_port_info(int p_idx) const{ + + Ref<Script> script = get_script(); + if (script.is_valid() && script->has_method(VisualScriptLanguage::singleton->_subcall)) { + MethodInfo mi = script->get_method_info(VisualScriptLanguage::singleton->_subcall); + return mi.return_val; + } + return PropertyInfo(); +} + + +String VisualScriptSubCall::get_caption() const { + + return "SubCall"; +} + + +String VisualScriptSubCall::get_text() const { + + Ref<Script> script = get_script(); + if (script.is_valid()) { + if (script->get_name()!=String()) + return script->get_name(); + if (script->get_path().is_resource_file()) + return script->get_path().get_file(); + return script->get_type(); + } + return ""; +} + +String VisualScriptSubCall::get_category() const { + + return "custom"; +} + +class VisualScriptNodeInstanceSubCall : public VisualScriptNodeInstance { +public: + + VisualScriptInstance* instance; + VisualScriptSubCall *subcall; + int input_args; + bool valid; + + //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) { + + if (!valid) { + r_error_str="Node requires a script with a _subcall(<args>) method to work."; + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + return 0; + } + *p_outputs[0]=subcall->call(VisualScriptLanguage::singleton->_subcall,p_inputs,input_args,r_error_str); + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptSubCall::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceSubCall * instance = memnew(VisualScriptNodeInstanceSubCall ); + instance->instance=p_instance; + Ref<Script> script = get_script(); + if (script.is_valid() && script->has_method(VisualScriptLanguage::singleton->_subcall)) { + instance->valid=true; + instance->input_args=get_input_value_port_count(); + } else { + instance->valid=false; + } + return instance; +} + + + +void VisualScriptSubCall::_bind_methods() { + + BIND_VMETHOD( MethodInfo(Variant::NIL,"_subcall",PropertyInfo(Variant::NIL,"arguments:Variant")) ); + +} + +VisualScriptSubCall::VisualScriptSubCall() { + + +} + + void register_visual_script_nodes() { - VisualScriptLanguage::singleton->add_register_func("data/variable",create_node_generic<VisualScriptVariable>); + VisualScriptLanguage::singleton->add_register_func("data/set_variable",create_node_generic<VisualScriptVariableGet>); + VisualScriptLanguage::singleton->add_register_func("data/get_variable",create_node_generic<VisualScriptVariableSet>); VisualScriptLanguage::singleton->add_register_func("data/constant",create_node_generic<VisualScriptConstant>); VisualScriptLanguage::singleton->add_register_func("data/global_constant",create_node_generic<VisualScriptGlobalConstant>); VisualScriptLanguage::singleton->add_register_func("data/math_constant",create_node_generic<VisualScriptMathConstant>); @@ -1414,6 +2444,9 @@ void register_visual_script_nodes() { VisualScriptLanguage::singleton->add_register_func("data/scene_node",create_node_generic<VisualScriptSceneNode>); VisualScriptLanguage::singleton->add_register_func("data/scene_tree",create_node_generic<VisualScriptSceneTree>); VisualScriptLanguage::singleton->add_register_func("data/resource_path",create_node_generic<VisualScriptResourcePath>); + 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("index/get_index",create_node_generic<VisualScriptIndexGet>); @@ -1448,4 +2481,5 @@ void register_visual_script_nodes() { VisualScriptLanguage::singleton->add_register_func("operators/logic/not",create_op_node<Variant::OP_NOT>); VisualScriptLanguage::singleton->add_register_func("operators/logic/in",create_op_node<Variant::OP_IN>); + } diff --git a/modules/visual_script/visual_script_nodes.h b/modules/visual_script/visual_script_nodes.h index 6080050d78..50f61ecfcc 100644 --- a/modules/visual_script/visual_script_nodes.h +++ b/modules/visual_script/visual_script_nodes.h @@ -14,6 +14,11 @@ class VisualScriptFunction : public VisualScriptNode { }; Vector<Argument> arguments; + + bool stack_less; + int stack_size; + + protected: bool _set(const StringName& p_name, const Variant& p_value); @@ -38,6 +43,7 @@ public: virtual String get_caption() const; virtual String get_text() const; + virtual String get_category() const { return "flow_control"; } void add_argument(Variant::Type p_type,const String& p_name,int p_index=-1); void set_argument_type(int p_argidx,Variant::Type p_type); @@ -47,7 +53,14 @@ public: void remove_argument(int p_argidx); int get_argument_count() const; - virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance); + + void set_stack_less(bool p_enable); + bool is_stack_less() const; + + void set_stack_size(int p_size); + int get_stack_size() const; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); VisualScriptFunction(); }; @@ -80,19 +93,20 @@ public: virtual String get_caption() const; virtual String get_text() const; + virtual String get_category() const { return "operators"; } void set_operator(Variant::Operator p_op); Variant::Operator get_operator() const; - virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance); + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); VisualScriptOperator(); }; -class VisualScriptVariable : public VisualScriptNode { +class VisualScriptVariableGet : public VisualScriptNode { - OBJ_TYPE(VisualScriptVariable,VisualScriptNode) + OBJ_TYPE(VisualScriptVariableGet,VisualScriptNode) StringName variable; @@ -118,15 +132,56 @@ public: virtual String get_caption() const; virtual String get_text() const; + virtual String get_category() const { return "data"; } void set_variable(StringName p_var); StringName get_variable() const; - virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance); + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); - VisualScriptVariable(); + VisualScriptVariableGet(); }; + +class VisualScriptVariableSet : public VisualScriptNode { + + OBJ_TYPE(VisualScriptVariableSet,VisualScriptNode) + + + StringName variable; +protected: + + virtual void _validate_property(PropertyInfo& property) const; + static void _bind_methods(); +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "data"; } + + void set_variable(StringName p_var); + StringName get_variable() const; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptVariableSet(); +}; + + class VisualScriptConstant : public VisualScriptNode { OBJ_TYPE(VisualScriptConstant,VisualScriptNode) @@ -156,6 +211,7 @@ public: virtual String get_caption() const; virtual String get_text() const; + virtual String get_category() const { return "data"; } void set_constant_type(Variant::Type p_type); Variant::Type get_constant_type() const; @@ -163,7 +219,7 @@ public: void set_constant_value(Variant p_value); Variant get_constant_value() const; - virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance); + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); VisualScriptConstant(); }; @@ -192,8 +248,9 @@ public: virtual String get_caption() const; virtual String get_text() const; + virtual String get_category() const { return "operators"; } - virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance); + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); VisualScriptIndexGet(); }; @@ -222,8 +279,9 @@ public: virtual String get_caption() const; virtual String get_text() const; + virtual String get_category() const { return "operators"; } - virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance); + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); VisualScriptIndexSet(); }; @@ -255,11 +313,12 @@ public: virtual String get_caption() const; virtual String get_text() const; + virtual String get_category() const { return "data"; } void set_global_constant(int p_which); int get_global_constant(); - virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance); + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); VisualScriptGlobalConstant(); }; @@ -283,6 +342,7 @@ public: private: static const char* const_name[MATH_CONSTANT_MAX]; + static double const_value[MATH_CONSTANT_MAX]; MathConstant constant; protected: static void _bind_methods(); @@ -304,11 +364,12 @@ public: virtual String get_caption() const; virtual String get_text() const; + virtual String get_category() const { return "data"; } void set_math_constant(MathConstant p_which); MathConstant get_math_constant(); - virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance); + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); VisualScriptMathConstant(); }; @@ -340,11 +401,12 @@ public: virtual String get_caption() const; virtual String get_text() const; + virtual String get_category() const { return "data"; } void set_singleton(const String &p_string); String get_singleton(); - virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance); + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); VisualScriptEngineSingleton(); }; @@ -378,11 +440,12 @@ public: virtual String get_caption() const; virtual String get_text() const; + virtual String get_category() const { return "data"; } void set_node_path(const NodePath &p_path); NodePath get_node_path(); - virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance); + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); VisualScriptSceneNode(); }; @@ -416,8 +479,9 @@ public: virtual String get_caption() const; virtual String get_text() const; + virtual String get_category() const { return "data"; } - virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance); + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); VisualScriptSceneTree(); }; @@ -450,16 +514,138 @@ public: virtual String get_caption() const; virtual String get_text() const; + virtual String get_category() const { return "data"; } void set_resource_path(const String &p_path); String get_resource_path(); - virtual VisualScriptNodeInstance* instance(VScriptInstance* p_instance); + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); VisualScriptResourcePath(); }; +class VisualScriptSelf : public VisualScriptNode { + + OBJ_TYPE(VisualScriptSelf,VisualScriptNode) + + +protected: + + static void _bind_methods(); +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "data"; } + + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptSelf(); +}; + + +class VisualScriptCustomNode: public VisualScriptNode { + + OBJ_TYPE(VisualScriptCustomNode,VisualScriptNode) + + +protected: + + virtual bool _use_builtin_script() const { return true; } + + static void _bind_methods(); +public: + + enum StartMode { //replicated for step + START_MODE_BEGIN_SEQUENCE, + START_MODE_CONTINUE_SEQUENCE, + START_MODE_RESUME_YIELD + }; + + enum { //replicated for step + STEP_SHIFT=1<<24, + STEP_MASK=STEP_SHIFT-1, + STEP_PUSH_STACK_BIT=STEP_SHIFT, //push bit to stack + STEP_GO_BACK_BIT=STEP_SHIFT<<1, //go back to previous node + STEP_NO_ADVANCE_BIT=STEP_SHIFT<<2, //do not advance past this node + STEP_EXIT_FUNCTION_BIT=STEP_SHIFT<<3, //return from function + STEP_YIELD_BIT=STEP_SHIFT<<4, //yield (will find VisualScriptFunctionState state in first working memory) + }; + + 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; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptCustomNode(); +}; + +class VisualScriptSubCall: public VisualScriptNode { + + OBJ_TYPE(VisualScriptSubCall,VisualScriptNode) + + +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; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptSubCall(); +}; + + void register_visual_script_nodes(); #endif // VISUAL_SCRIPT_NODES_H diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp new file mode 100644 index 0000000000..a6f84a97d9 --- /dev/null +++ b/modules/visual_script/visual_script_yield_nodes.cpp @@ -0,0 +1,622 @@ +#include "visual_script_yield_nodes.h" +#include "scene/main/scene_main_loop.h" +#include "os/os.h" +#include "scene/main/node.h" +#include "visual_script_nodes.h" + +////////////////////////////////////////// +////////////////YIELD/////////// +////////////////////////////////////////// + +int VisualScriptYield::get_output_sequence_port_count() const { + + return 1; +} + +bool VisualScriptYield::has_input_sequence_port() const{ + + return true; +} + +int VisualScriptYield::get_input_value_port_count() const{ + + return 0; +} +int VisualScriptYield::get_output_value_port_count() const{ + + return 0; +} + +String VisualScriptYield::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptYield::get_input_value_port_info(int p_idx) const{ + + return PropertyInfo(); +} + +PropertyInfo VisualScriptYield::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(); +} + + +String VisualScriptYield::get_caption() const { + + return "Wait"; +} + +String VisualScriptYield::get_text() const { + + switch (yield_mode) { + 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; + } + + return String(); +} + + +class VisualScriptNodeInstanceYield : public VisualScriptNodeInstance { +public: + + VisualScriptYield::YieldMode mode; + float wait_time; + + virtual int get_working_memory_size() const { return 1; } //yield needs at least 1 + //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) { + + if (p_start_mode==START_MODE_RESUME_YIELD) { + return 0; //resuming yield + } else { + //yield + + + SceneTree *tree = OS::get_singleton()->get_main_loop()->cast_to<SceneTree>(); + if (!tree) { + r_error_str="Main Loop is not SceneTree"; + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + return 0; + } + + Ref<VisualScriptFunctionState> state; + state.instance(); + + switch(mode) { + + 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; + + } + + *p_working_mem=state; + + return STEP_YIELD_BIT; + } + } + +}; + +VisualScriptNodeInstance* VisualScriptYield::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceYield * instance = memnew(VisualScriptNodeInstanceYield ); + //instance->instance=p_instance; + instance->mode=yield_mode; + instance->wait_time=wait_time; + return instance; +} + +void VisualScriptYield::set_yield_mode(YieldMode p_mode) { + + if (yield_mode==p_mode) + return; + yield_mode=p_mode; + ports_changed_notify(); + _change_notify(); +} + +VisualScriptYield::YieldMode VisualScriptYield::get_yield_mode(){ + + return yield_mode; +} + +void VisualScriptYield::set_wait_time(float p_time) { + + if (wait_time==p_time) + return; + wait_time=p_time; + ports_changed_notify(); + +} + +float VisualScriptYield::get_wait_time(){ + + return wait_time; +} + + +void VisualScriptYield::_validate_property(PropertyInfo& property) const { + + + if (property.name=="wait_time") { + if (yield_mode!=YIELD_WAIT) { + property.usage=0; + } + } +} + +void VisualScriptYield::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_yield_mode","mode"),&VisualScriptYield::set_yield_mode); + ObjectTypeDB::bind_method(_MD("get_yield_mode"),&VisualScriptYield::get_yield_mode); + + ObjectTypeDB::bind_method(_MD("set_wait_time","sec"),&VisualScriptYield::set_wait_time); + ObjectTypeDB::bind_method(_MD("get_wait_time"),&VisualScriptYield::get_wait_time); + + ADD_PROPERTY(PropertyInfo(Variant::INT,"mode",PROPERTY_HINT_ENUM,"Frame,FixedFrame,Time",PROPERTY_USAGE_NOEDITOR),_SCS("set_yield_mode"),_SCS("get_yield_mode")); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"wait_time"),_SCS("set_wait_time"),_SCS("get_wait_time")); + + + BIND_CONSTANT( YIELD_FRAME ); + BIND_CONSTANT( YIELD_FIXED_FRAME ); + BIND_CONSTANT( YIELD_WAIT ); + +} + +VisualScriptYield::VisualScriptYield() { + + yield_mode=YIELD_FRAME; + wait_time=1; + +} + + +template<VisualScriptYield::YieldMode MODE> +static Ref<VisualScriptNode> create_yield_node(const String& p_name) { + + Ref<VisualScriptYield> node; + node.instance(); + node->set_yield_mode(MODE); + return node; +} + +/////////////////////////////////////////////////// +////////////////YIELD SIGNAL////////////////////// +////////////////////////////////////////////////// + +int VisualScriptYieldSignal::get_output_sequence_port_count() const { + + return 1; +} + +bool VisualScriptYieldSignal::has_input_sequence_port() const{ + + return true; +} +#ifdef TOOLS_ENABLED + +static Node* _find_script_node(Node* p_edited_scene,Node* p_current_node,const Ref<Script> &script) { + + if (p_edited_scene!=p_current_node && p_current_node->get_owner()!=p_edited_scene) + return NULL; + + Ref<Script> scr = p_current_node->get_script(); + + if (scr.is_valid() && scr==script) + return p_current_node; + + for(int i=0;i<p_current_node->get_child_count();i++) { + Node *n = _find_script_node(p_edited_scene,p_current_node->get_child(i),script); + if (n) + return n; + } + + return NULL; +} + +#endif +Node *VisualScriptYieldSignal::_get_base_node() const { + +#ifdef TOOLS_ENABLED + Ref<Script> script = get_visual_script(); + if (!script.is_valid()) + return NULL; + + MainLoop * main_loop = OS::get_singleton()->get_main_loop(); + if (!main_loop) + return NULL; + + SceneTree *scene_tree = main_loop->cast_to<SceneTree>(); + + if (!scene_tree) + return NULL; + + Node *edited_scene = scene_tree->get_edited_scene_root(); + + if (!edited_scene) + return NULL; + + Node* script_node = _find_script_node(edited_scene,edited_scene,script); + + if (!script_node) + return NULL; + + if (!script_node->has_node(base_path)) + return NULL; + + Node *path_to = script_node->get_node(base_path); + + return path_to; +#else + + return NULL; +#endif +} + +StringName VisualScriptYieldSignal::_get_base_type() const { + + if (call_mode==CALL_MODE_SELF && get_visual_script().is_valid()) + return get_visual_script()->get_instance_base_type(); + else if (call_mode==CALL_MODE_NODE_PATH && get_visual_script().is_valid()) { + Node *path = _get_base_node(); + if (path) + return path->get_type(); + + } + + return base_type; +} + +int VisualScriptYieldSignal::get_input_value_port_count() const{ + + if (call_mode==CALL_MODE_INSTANCE) + return 1; + else + return 0; + +} +int VisualScriptYieldSignal::get_output_value_port_count() const{ + + + MethodInfo sr; + + if (!ObjectTypeDB::get_signal(_get_base_type(),signal,&sr)) + return 0; + + return sr.arguments.size(); + +} + +String VisualScriptYieldSignal::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptYieldSignal::get_input_value_port_info(int p_idx) const{ + + if (call_mode==CALL_MODE_INSTANCE) + return PropertyInfo(Variant::OBJECT,"instance"); + else + return PropertyInfo(); + +} + +PropertyInfo VisualScriptYieldSignal::get_output_value_port_info(int p_idx) const{ + + MethodInfo sr; + + if (!ObjectTypeDB::get_signal(_get_base_type(),signal,&sr)) + return PropertyInfo(); //no signal + ERR_FAIL_INDEX_V(p_idx,sr.arguments.size(),PropertyInfo()); + return sr.arguments[p_idx]; + +} + + +String VisualScriptYieldSignal::get_caption() const { + + static const char*cname[3]= { + "WaitSignal", + "WaitNodeSignal", + "WaitInstanceSigna;", + }; + + return cname[call_mode]; +} + +String VisualScriptYieldSignal::get_text() const { + + if (call_mode==CALL_MODE_SELF) + return " "+String(signal)+"()"; + else + return " "+_get_base_type()+"."+String(signal)+"()"; + +} + + +void VisualScriptYieldSignal::set_base_type(const StringName& p_type) { + + if (base_type==p_type) + return; + + base_type=p_type; + + _change_notify(); + ports_changed_notify(); +} + +StringName VisualScriptYieldSignal::get_base_type() const{ + + return base_type; +} + +void VisualScriptYieldSignal::set_signal(const StringName& p_type){ + + if (signal==p_type) + return; + + signal=p_type; + + _change_notify(); + ports_changed_notify(); +} +StringName VisualScriptYieldSignal::get_signal() const { + + + return signal; +} + +void VisualScriptYieldSignal::set_base_path(const NodePath& p_type) { + + if (base_path==p_type) + return; + + base_path=p_type; + + _change_notify(); + ports_changed_notify(); +} + +NodePath VisualScriptYieldSignal::get_base_path() const { + + return base_path; +} + + +void VisualScriptYieldSignal::set_call_mode(CallMode p_mode) { + + if (call_mode==p_mode) + return; + + call_mode=p_mode; + + _change_notify(); + ports_changed_notify(); + +} + +VisualScriptYieldSignal::CallMode VisualScriptYieldSignal::get_call_mode() const { + + return call_mode; +} + + +void VisualScriptYieldSignal::_validate_property(PropertyInfo& property) const { + + if (property.name=="signal/base_type") { + if (call_mode!=CALL_MODE_INSTANCE) { + property.usage=PROPERTY_USAGE_NOEDITOR; + } + } + + + if (property.name=="signal/node_path") { + if (call_mode!=CALL_MODE_NODE_PATH) { + property.usage=0; + } else { + + Node *bnode = _get_base_node(); + if (bnode) { + property.hint_string=bnode->get_path(); //convert to loong string + } else { + + } + } + } + + if (property.name=="signal/signal") { + property.hint=PROPERTY_HINT_ENUM; + + + List<MethodInfo> methods; + + ObjectTypeDB::get_signal_list(_get_base_type(),&methods); + + List<String> mstring; + for (List<MethodInfo>::Element *E=methods.front();E;E=E->next()) { + if (E->get().name.begins_with("_")) + continue; + mstring.push_back(E->get().name.get_slice(":",0)); + } + + mstring.sort(); + + String ml; + for (List<String>::Element *E=mstring.front();E;E=E->next()) { + + if (ml!=String()) + ml+=","; + ml+=E->get(); + } + + property.hint_string=ml; + } + + +} + + +void VisualScriptYieldSignal::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_base_type","base_type"),&VisualScriptYieldSignal::set_base_type); + ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptYieldSignal::get_base_type); + + ObjectTypeDB::bind_method(_MD("set_signal","signal"),&VisualScriptYieldSignal::set_signal); + ObjectTypeDB::bind_method(_MD("get_signal"),&VisualScriptYieldSignal::get_signal); + + ObjectTypeDB::bind_method(_MD("set_call_mode","mode"),&VisualScriptYieldSignal::set_call_mode); + ObjectTypeDB::bind_method(_MD("get_call_mode"),&VisualScriptYieldSignal::get_call_mode); + + ObjectTypeDB::bind_method(_MD("set_base_path","base_path"),&VisualScriptYieldSignal::set_base_path); + ObjectTypeDB::bind_method(_MD("get_base_path"),&VisualScriptYieldSignal::get_base_path); + + + + String bt; + for(int i=0;i<Variant::VARIANT_MAX;i++) { + if (i>0) + bt+=","; + + 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::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")); + + + BIND_CONSTANT( CALL_MODE_SELF ); + BIND_CONSTANT( CALL_MODE_NODE_PATH); + BIND_CONSTANT( CALL_MODE_INSTANCE); + +} + +class VisualScriptNodeInstanceYieldSignal : public VisualScriptNodeInstance { +public: + + + VisualScriptYieldSignal::CallMode call_mode; + NodePath node_path; + int output_args; + StringName signal; + + VisualScriptYieldSignal *node; + VisualScriptInstance *instance; + + + + virtual int get_working_memory_size() const { return 1; } + //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 true; } + + 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) { + + if (p_start_mode==START_MODE_RESUME_YIELD) { + return 0; //resuming yield + } else { + //yield + + Object * object; + + switch(call_mode) { + + case VisualScriptYieldSignal::CALL_MODE_SELF: { + + object=instance->get_owner_ptr(); + + } break; + case VisualScriptYieldSignal::CALL_MODE_NODE_PATH: { + + Node* node = instance->get_owner_ptr()->cast_to<Node>(); + if (!node) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Base object is not a Node!"; + return 0; + } + + Node* another = node->get_node(node_path); + if (!node) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Path does not lead Node!"; + return 0; + } + + object=another; + + } break; + case VisualScriptYieldSignal::CALL_MODE_INSTANCE: { + + object = *p_inputs[0]; + if (!object) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Supplied instance input is null."; + return 0; + + } + + } break; + + } + + Ref<VisualScriptFunctionState> state; + state.instance(); + + state->connect_to_signal(object,signal,Array()); + + *p_working_mem=state; + + return STEP_YIELD_BIT; + } + + + } + + +}; + +VisualScriptNodeInstance* VisualScriptYieldSignal::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceYieldSignal * instance = memnew(VisualScriptNodeInstanceYieldSignal ); + instance->node=this; + instance->instance=p_instance; + instance->signal=signal; + instance->call_mode=call_mode; + instance->node_path=base_path; + instance->output_args = get_output_value_port_count(); + return instance; +} +VisualScriptYieldSignal::VisualScriptYieldSignal() { + + call_mode=CALL_MODE_INSTANCE; + base_type="Object"; + +} + +template<VisualScriptYieldSignal::CallMode cmode> +static Ref<VisualScriptNode> create_yield_signal_node(const String& p_name) { + + Ref<VisualScriptYieldSignal> node; + node.instance(); + node->set_call_mode(cmode); + return node; +} + +void register_visual_script_yield_nodes() { + + VisualScriptLanguage::singleton->add_register_func("functions/wait/wait_frame",create_yield_node<VisualScriptYield::YIELD_FRAME>); + 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>); + +} diff --git a/modules/visual_script/visual_script_yield_nodes.h b/modules/visual_script/visual_script_yield_nodes.h new file mode 100644 index 0000000000..a7e200305d --- /dev/null +++ b/modules/visual_script/visual_script_yield_nodes.h @@ -0,0 +1,127 @@ +#ifndef VISUAL_SCRIPT_YIELD_NODES_H +#define VISUAL_SCRIPT_YIELD_NODES_H + +#include "visual_script.h" + +class VisualScriptYield : public VisualScriptNode { + + OBJ_TYPE(VisualScriptYield,VisualScriptNode) +public: + + enum YieldMode { + YIELD_FRAME, + YIELD_FIXED_FRAME, + YIELD_WAIT + + }; +private: + + YieldMode yield_mode; + float wait_time; + + +protected: + + virtual void _validate_property(PropertyInfo& property) const; + + static void _bind_methods(); +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "functions"; } + + void set_yield_mode(YieldMode p_mode); + YieldMode get_yield_mode(); + + void set_wait_time(float p_time); + float get_wait_time(); + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptYield(); +}; +VARIANT_ENUM_CAST( VisualScriptYield::YieldMode ) + +class VisualScriptYieldSignal : public VisualScriptNode { + + OBJ_TYPE(VisualScriptYieldSignal,VisualScriptNode) +public: + enum CallMode { + CALL_MODE_SELF, + CALL_MODE_NODE_PATH, + CALL_MODE_INSTANCE, + + }; +private: + + CallMode call_mode; + StringName base_type; + NodePath base_path; + StringName signal; + + Node *_get_base_node() const; + StringName _get_base_type() const; + + +protected: + virtual void _validate_property(PropertyInfo& property) const; + + static void _bind_methods(); + +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "functions"; } + + void set_base_type(const StringName& p_type); + StringName get_base_type() const; + + void set_signal(const StringName& p_type); + StringName get_signal() const; + + void set_base_path(const NodePath& p_type); + NodePath get_base_path() const; + + void set_call_mode(CallMode p_mode); + CallMode get_call_mode() const; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptYieldSignal(); +}; + +VARIANT_ENUM_CAST(VisualScriptYieldSignal::CallMode ); + +void register_visual_script_yield_nodes(); + +#endif // VISUAL_SCRIPT_YIELD_NODES_H |