diff options
Diffstat (limited to 'modules')
26 files changed, 7010 insertions, 1113 deletions
diff --git a/modules/enet/networked_multiplayer_enet.cpp b/modules/enet/networked_multiplayer_enet.cpp index 5ddbb83534..18a4347edf 100644 --- a/modules/enet/networked_multiplayer_enet.cpp +++ b/modules/enet/networked_multiplayer_enet.cpp @@ -26,7 +26,7 @@ Error NetworkedMultiplayerENet::create_server(int p_port, int p_max_clients, int ERR_FAIL_COND_V(active,ERR_ALREADY_IN_USE); ENetAddress address; - address.host = ENET_HOST_ANY; + address.host = bind_ip; address.port = p_port; @@ -610,12 +610,12 @@ void NetworkedMultiplayerENet::_bind_methods() { ObjectTypeDB::bind_method(_MD("close_connection"),&NetworkedMultiplayerENet::close_connection); ObjectTypeDB::bind_method(_MD("set_compression_mode","mode"),&NetworkedMultiplayerENet::set_compression_mode); ObjectTypeDB::bind_method(_MD("get_compression_mode"),&NetworkedMultiplayerENet::get_compression_mode); + ObjectTypeDB::bind_method(_MD("set_bind_ip", "ip"),&NetworkedMultiplayerENet::set_bind_ip); BIND_CONSTANT( COMPRESS_NONE ); BIND_CONSTANT( COMPRESS_RANGE_CODER ); BIND_CONSTANT( COMPRESS_FASTLZ ); BIND_CONSTANT( COMPRESS_ZLIB ); - } @@ -635,9 +635,16 @@ NetworkedMultiplayerENet::NetworkedMultiplayerENet(){ enet_compressor.decompress=enet_decompress; enet_compressor.destroy=enet_compressor_destroy; + bind_ip=ENET_HOST_ANY; } NetworkedMultiplayerENet::~NetworkedMultiplayerENet(){ close_connection(); } + +// sets IP for ENet to bind when using create_server +// if no IP is set, then ENet bind to ENET_HOST_ANY +void NetworkedMultiplayerENet::set_bind_ip(const IP_Address& p_ip){ + bind_ip=p_ip.host; +} diff --git a/modules/enet/networked_multiplayer_enet.h b/modules/enet/networked_multiplayer_enet.h index dc86058cbb..59863c1f78 100644 --- a/modules/enet/networked_multiplayer_enet.h +++ b/modules/enet/networked_multiplayer_enet.h @@ -65,6 +65,7 @@ private: static void enet_compressor_destroy(void * context); void _setup_compressor(); + enet_uint32 bind_ip; protected: static void _bind_methods(); public: @@ -103,6 +104,8 @@ public: NetworkedMultiplayerENet(); ~NetworkedMultiplayerENet(); + + void set_bind_ip(const IP_Address& p_ip); }; VARIANT_ENUM_CAST(NetworkedMultiplayerENet::CompressionMode); diff --git a/modules/enet/win32.c b/modules/enet/win32.c index d77fa9a49a..15edd7acbb 100644 --- a/modules/enet/win32.c +++ b/modules/enet/win32.c @@ -28,7 +28,9 @@ enet_initialize (void) return -1; } +#ifndef WINRT_ENABLED timeBeginPeriod (1); +#endif return 0; } @@ -36,11 +38,22 @@ enet_initialize (void) void enet_deinitialize (void) { +#ifndef WINRT_ENABLED timeEndPeriod (1); +#endif WSACleanup (); } +#ifdef WINRT_ENABLED +enet_uint32 +timeGetTime() { + ULONGLONG ticks = GetTickCount64(); + return (enet_uint32)ticks; +} +#endif + + enet_uint32 enet_host_random_seed (void) { diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp index 5b74dab889..2a80531ec5 100644 --- a/modules/gdscript/gd_editor.cpp +++ b/modules/gdscript/gd_editor.cpp @@ -47,16 +47,14 @@ void GDScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const { Ref<Script> GDScriptLanguage::get_template(const String& p_class_name, const String& p_base_class_name) const { String _template = String()+ - "\nextends %BASE%\n\n"+ - "# member variables here, example:\n"+ - "# var a=2\n"+ - "# var b=\"textvar\"\n\n"+ + "extends %BASE%\n\n"+ + "# class member variables go here, for example:\n"+ + "# var a = 2\n"+ + "# var b = \"textvar\"\n\n"+ "func _ready():\n"+ "\t# Called every time the node is added to the scene.\n"+ "\t# Initialization here\n"+ - "\tpass\n"+ - "\n"+ - "\n"; + "\tpass\n"; _template = _template.replace("%BASE%",p_base_class_name); diff --git a/modules/gdscript/gd_function.cpp b/modules/gdscript/gd_function.cpp index b2cc6341c1..094e21bb4f 100644 --- a/modules/gdscript/gd_function.cpp +++ b/modules/gdscript/gd_function.cpp @@ -1437,7 +1437,7 @@ void GDFunctionState::_bind_methods() { ObjectTypeDB::bind_method(_MD("resume:Variant","arg"),&GDFunctionState::resume,DEFVAL(Variant())); ObjectTypeDB::bind_method(_MD("is_valid"),&GDFunctionState::is_valid); - ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"_signal_callback",&GDFunctionState::_signal_callback,MethodInfo("_signal_callback")); + ObjectTypeDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"_signal_callback",&GDFunctionState::_signal_callback,MethodInfo("_signal_callback")); } diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index 13fbfb6ec0..0ea10950df 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -179,6 +179,15 @@ bool GDScript::can_instance() const { } +Ref<Script> GDScript::get_base_script() const { + + if (_base) { + return Ref<GDScript>( _base ); + } else { + return Ref<Script>(); + } +} + StringName GDScript::get_instance_base_type() const { if (native.is_valid()) @@ -742,7 +751,7 @@ void GDScript::_get_property_list(List<PropertyInfo> *p_properties) const { void GDScript::_bind_methods() { - ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"new",&GDScript::_new,MethodInfo(Variant::OBJECT,"new")); + ObjectTypeDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"new",&GDScript::_new,MethodInfo(Variant::OBJECT,"new")); ObjectTypeDB::bind_method(_MD("get_as_byte_code"),&GDScript::get_as_byte_code); diff --git a/modules/gdscript/gd_script.h b/modules/gdscript/gd_script.h index 856211b2fd..0c3e1eb614 100644 --- a/modules/gdscript/gd_script.h +++ b/modules/gdscript/gd_script.h @@ -162,6 +162,8 @@ public: Variant _new(const Variant** p_args,int p_argcount,Variant::CallError& r_error); virtual bool can_instance() const; + virtual Ref<Script> get_base_script() const; + virtual StringName get_instance_base_type() const; // this may not work in all scripts, will return empty if so virtual ScriptInstance* instance_create(Object *p_this); virtual bool instance_has(const Object *p_this) const; diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp index f3beabceb8..9bdad6713d 100644 --- a/modules/gridmap/grid_map_editor_plugin.cpp +++ b/modules/gridmap/grid_map_editor_plugin.cpp @@ -212,6 +212,18 @@ void GridMapEditor::_menu_option(int p_option) { _update_areas_display(); update_areas(); } break; + case MENU_OPTION_SELECTION_DUPLICATE: + if (!(selection.active && input_action==INPUT_NONE)) + return; + if (last_mouseover==Vector3(-1,-1,-1)) //nono mouseovering anythin + break; + + input_action=INPUT_DUPLICATE; + selection.click=last_mouseover; + selection.current=last_mouseover; + selection.duplicate_rot=0; + _update_duplicate_indicator(); + break; case MENU_OPTION_SELECTION_CLEAR: { if (!selection.active) return; @@ -377,7 +389,9 @@ bool GridMapEditor::do_input_action(Camera* p_camera,const Point2& p_point,bool int item=node->get_cell_item(cell[0],cell[1],cell[2]); if (item>=0) { selected_pallete=item; + theme_pallete->set_current(item); update_pallete(); + _update_cursor_instance(); } return true; } if (input_action==INPUT_PAINT) { @@ -530,29 +544,6 @@ bool GridMapEditor::forward_spatial_input_event(Camera* p_camera,const InputEven if (edit_mode->get_selected()==0) { // regular click switch (p_event.type) { - case InputEvent::KEY: { - - if (p_event.key.pressed && p_event.key.scancode==KEY_D && p_event.key.mod.shift && selection.active && input_action==INPUT_NONE) { - - if (last_mouseover==Vector3(-1,-1,-1)) //nono mouseovering anythin - return false; - - input_action=INPUT_DUPLICATE; - selection.click=last_mouseover; - selection.current=last_mouseover; - selection.duplicate_rot=0; - _update_duplicate_indicator(); - - - } - - if (p_event.key.pressed && p_event.key.scancode==KEY_DELETE && selection.active) { - - _delete_selection(); - return true; - } - - } break; case InputEvent::MOUSE_BUTTON: { if (p_event.mouse_button.button_index==BUTTON_WHEEL_UP && (p_event.mouse_button.mod.command || p_event.mouse_button.mod.shift)) { @@ -851,6 +842,11 @@ void GridMapEditor::edit(GridMap *p_gridmap) { VS *vs = VS::get_singleton(); last_mouseover=Vector3(-1,-1,-1); + input_action=INPUT_NONE; + selection.active=false; + _update_selection_transform(); + _update_duplicate_indicator(); + spatial_editor = editor->get_editor_plugin_screen()->cast_to<SpatialEditorPlugin>(); if (!node) { @@ -1247,7 +1243,8 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { options->get_popup()->add_item("Create Exterior Connector",MENU_OPTION_SELECTION_MAKE_EXTERIOR_CONNECTOR); options->get_popup()->add_item("Erase Area",MENU_OPTION_REMOVE_AREA); options->get_popup()->add_separator(); - options->get_popup()->add_item("Selection -> Clear",MENU_OPTION_SELECTION_CLEAR); + options->get_popup()->add_item("Selection -> Duplicate",MENU_OPTION_SELECTION_DUPLICATE,KEY_MASK_SHIFT+KEY_INSERT); + options->get_popup()->add_item("Selection -> Clear",MENU_OPTION_SELECTION_CLEAR,KEY_MASK_SHIFT+KEY_DELETE); //options->get_popup()->add_separator(); //options->get_popup()->add_item("Configure",MENU_OPTION_CONFIGURE); @@ -1266,7 +1263,7 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { settings_pick_distance->set_max(10000.0f); settings_pick_distance->set_min(500.0f); settings_pick_distance->set_step(1.0f); - settings_pick_distance->set_val(EDITOR_DEF("gridmap_editor/pick_distance", 5000.0)); + settings_pick_distance->set_val(EDITOR_DEF("grid_map/pick_distance", 5000.0)); settings_vbc->add_margin_child("Pick Distance:", settings_pick_distance); clip_mode=CLIP_DISABLED; diff --git a/modules/gridmap/grid_map_editor_plugin.h b/modules/gridmap/grid_map_editor_plugin.h index fc43866ef3..535c51bcbf 100644 --- a/modules/gridmap/grid_map_editor_plugin.h +++ b/modules/gridmap/grid_map_editor_plugin.h @@ -167,6 +167,7 @@ class GridMapEditor : public VBoxContainer { MENU_OPTION_DUPLICATE_SELECTS, MENU_OPTION_SELECTION_MAKE_AREA, MENU_OPTION_SELECTION_MAKE_EXTERIOR_CONNECTOR, + MENU_OPTION_SELECTION_DUPLICATE, MENU_OPTION_SELECTION_CLEAR, MENU_OPTION_REMOVE_AREA, MENU_OPTION_GRIDMAP_SETTINGS diff --git a/modules/visual_script/register_types.cpp b/modules/visual_script/register_types.cpp index 6e60b6a314..ad54149b51 100644 --- a/modules/visual_script/register_types.cpp +++ b/modules/visual_script/register_types.cpp @@ -36,6 +36,7 @@ #include "visual_script_builtin_funcs.h" #include "visual_script_flow_control.h" #include "visual_script_yield_nodes.h" +#include "visual_script_expression.h" VisualScriptLanguage *visual_script_language=NULL; @@ -43,6 +44,10 @@ VisualScriptLanguage *visual_script_language=NULL; void register_visual_script_types() { + visual_script_language=memnew( VisualScriptLanguage ); + //script_language_gd->init(); + ScriptServer::register_language(visual_script_language); + ObjectTypeDB::register_type<VisualScript>(); ObjectTypeDB::register_virtual_type<VisualScriptNode>(); ObjectTypeDB::register_virtual_type<VisualScriptFunctionState>(); @@ -54,7 +59,9 @@ void register_visual_script_types() { ObjectTypeDB::register_type<VisualScriptIndexGet>(); ObjectTypeDB::register_type<VisualScriptIndexSet>(); ObjectTypeDB::register_type<VisualScriptGlobalConstant>(); + ObjectTypeDB::register_type<VisualScriptClassConstant>(); ObjectTypeDB::register_type<VisualScriptMathConstant>(); + ObjectTypeDB::register_type<VisualScriptBasicTypeConstant>(); ObjectTypeDB::register_type<VisualScriptEngineSingleton>(); ObjectTypeDB::register_type<VisualScriptSceneNode>(); ObjectTypeDB::register_type<VisualScriptSceneTree>(); @@ -62,6 +69,15 @@ void register_visual_script_types() { ObjectTypeDB::register_type<VisualScriptSelf>(); ObjectTypeDB::register_type<VisualScriptCustomNode>(); ObjectTypeDB::register_type<VisualScriptSubCall>(); + ObjectTypeDB::register_type<VisualScriptComment>(); + ObjectTypeDB::register_type<VisualScriptConstructor>(); + ObjectTypeDB::register_type<VisualScriptLocalVar>(); + ObjectTypeDB::register_type<VisualScriptLocalVarSet>(); + ObjectTypeDB::register_type<VisualScriptInputAction>(); + ObjectTypeDB::register_type<VisualScriptDeconstruct>(); + ObjectTypeDB::register_type<VisualScriptPreload>(); + ObjectTypeDB::register_type<VisualScriptTypeCast>(); + ObjectTypeDB::register_type<VisualScriptFunctionCall>(); ObjectTypeDB::register_type<VisualScriptPropertySet>(); @@ -75,22 +91,22 @@ void register_visual_script_types() { ObjectTypeDB::register_type<VisualScriptIterator>(); ObjectTypeDB::register_type<VisualScriptSequence>(); ObjectTypeDB::register_type<VisualScriptInputFilter>(); - ObjectTypeDB::register_type<VisualScriptInputSelector>(); + ObjectTypeDB::register_type<VisualScriptSwitch >(); ObjectTypeDB::register_type<VisualScriptYield>(); ObjectTypeDB::register_type<VisualScriptYieldSignal>(); ObjectTypeDB::register_type<VisualScriptBuiltinFunc>(); - visual_script_language=memnew( VisualScriptLanguage ); - //script_language_gd->init(); - ScriptServer::register_language(visual_script_language); + + ObjectTypeDB::register_type<VisualScriptExpression>(); register_visual_script_nodes(); register_visual_script_func_nodes(); register_visual_script_builtin_func_node(); register_visual_script_flow_control_nodes(); register_visual_script_yield_nodes(); + register_visual_script_expression_node(); #ifdef TOOLS_ENABLED VisualScriptEditor::register_editor(); @@ -102,8 +118,13 @@ void register_visual_script_types() { void unregister_visual_script_types() { + unregister_visual_script_nodes(); + ScriptServer::unregister_language(visual_script_language); +#ifdef TOOLS_ENABLED + VisualScriptEditor::free_clipboard(); +#endif if (visual_script_language) memdelete( visual_script_language ); diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index 82e538d781..bd042c8989 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -1,9 +1,9 @@ #include "visual_script.h" #include "visual_script_nodes.h" #include "scene/main/node.h" - +#include "os/os.h" #include "globals.h" -#define SCRIPT_VARIABLES_PREFIX "script_variables/" + //used by editor, this is not really saved @@ -31,15 +31,25 @@ void VisualScriptNode::_notification(int p_what) { void VisualScriptNode::ports_changed_notify(){ + default_input_values.resize( MAX(default_input_values.size(),get_input_value_port_count()) ); //let it grow as big as possible, we don't want to lose values on resize + emit_signal("ports_changed"); + } -void VisualScriptNode::set_default_input_value(int p_port,const Variant& p_value) { +void VisualScriptNode::set_default_input_value(int p_port,const Variant& p_value) { ERR_FAIL_INDEX(p_port,default_input_values.size()); default_input_values[p_port]=p_value; + +#ifdef TOOLS_ENABLED + for (Set<VisualScript*>::Element *E=scripts_used.front();E;E=E->next()) { + E->get()->set_edited(true); + } +#endif + } Variant VisualScriptNode::get_default_input_value(int p_port) const { @@ -54,35 +64,40 @@ void VisualScriptNode::_set_default_input_values(Array p_values) { default_input_values=p_values; } -Array VisualScriptNode::_get_default_input_values() const { - //validate on save, since on load there is little info about this +void VisualScriptNode::validate_input_default_values() { + - Array saved_values; + + default_input_values.resize(get_input_value_port_count()); //actually validate on save for(int i=0;i<get_input_value_port_count();i++) { Variant::Type expected = get_input_value_port_info(i).type; - if (i>=default_input_values.size()) { + if (expected==Variant::NIL || expected==default_input_values[i].get_type()) { + continue; + } else { + //not the same, reconvert Variant::CallError ce; - saved_values.push_back(Variant::construct(expected,NULL,0,ce,false)); - } else { - - if (expected==Variant::NIL || expected==default_input_values[i].get_type()) { - saved_values.push_back(default_input_values[i]); - } else { - //not the same, reconvert - Variant::CallError ce; - Variant existing = default_input_values[i]; - const Variant *existingp=&existing; - saved_values.push_back( Variant::construct(expected,&existingp,1,ce,false) ); + Variant existing = default_input_values[i]; + const Variant *existingp=&existing; + default_input_values[i] = Variant::construct(expected,&existingp,1,ce,false); + if (ce.error!=Variant::CallError::CALL_OK) { + //could not convert? force.. + default_input_values[i] = Variant::construct(expected,NULL,0,ce,false); } } } - return saved_values; +} + +Array VisualScriptNode::_get_default_input_values() const { + + //validate on save, since on load there is little info about this + + return default_input_values; } @@ -99,6 +114,19 @@ void VisualScriptNode::_bind_methods() { ADD_SIGNAL(MethodInfo("ports_changed")); } +VisualScriptNode::TypeGuess VisualScriptNode::guess_output_type(TypeGuess* p_inputs,int p_output) const { + + PropertyInfo pinfo = get_output_value_port_info(p_output); + + TypeGuess tg; + + tg.type=pinfo.type; + if (pinfo.hint==PROPERTY_HINT_RESOURCE_TYPE) { + tg.obj_type=pinfo.hint_string; + } + + return tg; +} Ref<VisualScript> VisualScriptNode::get_visual_script() const { @@ -106,7 +134,6 @@ Ref<VisualScript> VisualScriptNode::get_visual_script() const { return Ref<VisualScript>(scripts_used.front()->get()); return Ref<VisualScript>(); - } VisualScriptNode::VisualScriptNode() { @@ -126,15 +153,15 @@ VisualScriptNodeInstance::VisualScriptNodeInstance() { VisualScriptNodeInstance::~VisualScriptNodeInstance() { if (sequence_outputs) { - memdelete(sequence_outputs); + memdelete_arr(sequence_outputs); } if (input_ports) { - memdelete(input_ports); + memdelete_arr(input_ports); } if (output_ports) { - memdelete(output_ports); + memdelete_arr(output_ports); } } @@ -224,6 +251,7 @@ int VisualScript::get_function_node_id(const StringName& p_name) const { void VisualScript::_node_ports_changed(int p_id) { + StringName function; for (Map<StringName,Function>::Element *E=functions.front();E;E=E->next()) { @@ -239,6 +267,10 @@ void VisualScript::_node_ports_changed(int p_id) { Function &func = functions[function]; Ref<VisualScriptNode> vsn = func.nodes[p_id].node; + if (OS::get_singleton()->get_main_loop() && OS::get_singleton()->get_main_loop()->cast_to<SceneTree>() && OS::get_singleton()->get_main_loop()->cast_to<SceneTree>()->is_editor_hint()) { + vsn->validate_input_default_values(); //force validate default values when editing on editor + } + //must revalidate all the functions { @@ -542,6 +574,23 @@ bool VisualScript::is_input_value_port_connected(const StringName& p_func,int p_ return false; } +bool VisualScript::get_input_value_port_connection_source(const StringName& p_func,int p_node,int p_port,int *r_node,int *r_port) const { + + ERR_FAIL_COND_V(!functions.has(p_func),false); + const Function &func = functions[p_func]; + + for (const Set<DataConnection>::Element *E=func.data_connections.front();E;E=E->next()) { + if (E->get().to_node==p_node && E->get().to_port==p_port) { + *r_node=E->get().from_node; + *r_port=E->get().from_port; + return true; + } + } + + return false; + +} + void VisualScript::get_data_connection_list(const StringName& p_func,List<DataConnection> *r_connection) const { ERR_FAIL_COND(!functions.has(p_func)); @@ -552,7 +601,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) { +void VisualScript::add_variable(const StringName& p_name,const Variant& p_default_value,bool p_export) { ERR_FAIL_COND( instances.size() ); ERR_FAIL_COND(!String(p_name).is_valid_identifier()); @@ -563,10 +612,9 @@ void VisualScript::add_variable(const StringName& p_name,const Variant& p_defaul v.info.type=p_default_value.get_type(); v.info.name=p_name; v.info.hint=PROPERTY_HINT_NONE; + v._export=p_export; variables[p_name]=v; - script_variable_remap[SCRIPT_VARIABLES_PREFIX+String(p_name)]=p_name; - #ifdef TOOLS_ENABLED _update_placeholders(); @@ -583,7 +631,6 @@ 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(); @@ -600,6 +647,7 @@ void VisualScript::set_variable_default_value(const StringName& p_name,const Var _update_placeholders(); #endif + } Variant VisualScript::get_variable_default_value(const StringName& p_name) const{ @@ -626,6 +674,21 @@ PropertyInfo VisualScript::get_variable_info(const StringName& p_name) const{ return variables[p_name].info; } +void VisualScript::set_variable_export(const StringName& p_name,bool p_export) { + + ERR_FAIL_COND(!variables.has(p_name)); + + variables[p_name]._export=p_export; +} + +bool VisualScript::get_variable_export(const StringName& p_name) const { + + ERR_FAIL_COND_V(!variables.has(p_name),false); + return variables[p_name]._export; + +} + + void VisualScript::_set_variable_info(const StringName& p_name,const Dictionary& p_info) { PropertyInfo pinfo; @@ -836,6 +899,10 @@ StringName VisualScript::get_instance_base_type() const { return base_type; } +Ref<Script> VisualScript::get_base_script() const { + return Ref<Script>(); // no inheritance in visual script +} + #ifdef TOOLS_ENABLED void VisualScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) { @@ -854,8 +921,11 @@ void VisualScript::_update_placeholders() { for (Map<StringName,Variable>::Element *E=variables.front();E;E=E->next()) { + if (!E->get()._export) + continue; + PropertyInfo p = E->get().info; - p.name=SCRIPT_VARIABLES_PREFIX+String(E->key()); + p.name=String(E->key()); pinfo.push_back(p); values[p.name]=E->get().default_value; } @@ -887,8 +957,11 @@ ScriptInstance* VisualScript::instance_create(Object *p_this) { for (Map<StringName,Variable>::Element *E=variables.front();E;E=E->next()) { + if (!E->get()._export) + continue; + PropertyInfo p = E->get().info; - p.name=SCRIPT_VARIABLES_PREFIX+String(E->key()); + p.name=String(E->key()); pinfo.push_back(p); values[p.name]=E->get().default_value; } @@ -986,10 +1059,10 @@ void VisualScript::get_script_signal_list(List<MethodInfo> *r_signals) const { bool VisualScript::get_property_default_value(const StringName& p_property,Variant& r_value) const { - if (!script_variable_remap.has(p_property)) + if (!variables.has(p_property)) return false; - r_value=variables[ script_variable_remap[p_property] ].default_value; + r_value=variables[ p_property ].default_value; return true; } void VisualScript::get_script_method_list(List<MethodInfo> *p_list) const { @@ -1051,11 +1124,27 @@ void VisualScript::get_script_property_list(List<PropertyInfo> *p_list) const { get_variable_list(&vars); for (List<StringName>::Element *E=vars.front();E;E=E->next()) { - + if (!variables[E->get()]._export) + continue; p_list->push_back(variables[E->get()].info); } } +#ifdef TOOLS_ENABLED +bool VisualScript::are_subnodes_edited() const { + + for(const Map<StringName,Function>::Element *E=functions.front();E;E=E->next()) { + + for (const Map<int,Function::NodeData>::Element *F=E->get().nodes.front();F;F=F->next()) { + if (F->get().node->is_edited()) { + return true; + } + } + } + + return false; +} +#endif void VisualScript::_set_data(const Dictionary& p_data) { @@ -1072,6 +1161,7 @@ void VisualScript::_set_data(const Dictionary& p_data) { add_variable(name); _set_variable_info(name,v); set_variable_default_value(name,v["default_value"]); + set_variable_export(name,v.has("export") && bool(v["export"])); } @@ -1142,6 +1232,7 @@ Dictionary VisualScript::_get_data() const{ Dictionary var = _get_variable_info(E->key()); var["name"]=E->key(); //make sure it's the right one var["default_value"]=E->get().default_value; + var["export"]=E->get()._export; vars.push_back(var); } d["variables"]=vars; @@ -1252,13 +1343,15 @@ void VisualScript::_bind_methods() { ObjectTypeDB::bind_method(_MD("data_disconnect","func","from_node","from_port","to_node","to_port"),&VisualScript::data_disconnect); ObjectTypeDB::bind_method(_MD("has_data_connection","func","from_node","from_port","to_node","to_port"),&VisualScript::has_data_connection); - ObjectTypeDB::bind_method(_MD("add_variable","name","default_value"),&VisualScript::add_variable,DEFVAL(Variant())); + ObjectTypeDB::bind_method(_MD("add_variable","name","default_value","export"),&VisualScript::add_variable,DEFVAL(Variant()),DEFVAL(false)); ObjectTypeDB::bind_method(_MD("has_variable","name"),&VisualScript::has_variable); ObjectTypeDB::bind_method(_MD("remove_variable","name"),&VisualScript::remove_variable); ObjectTypeDB::bind_method(_MD("set_variable_default_value","name","value"),&VisualScript::set_variable_default_value); ObjectTypeDB::bind_method(_MD("get_variable_default_value","name"),&VisualScript::get_variable_default_value); ObjectTypeDB::bind_method(_MD("set_variable_info","name","value"),&VisualScript::_set_variable_info); ObjectTypeDB::bind_method(_MD("get_variable_info","name"),&VisualScript::_get_variable_info); + ObjectTypeDB::bind_method(_MD("set_variable_export","name","enable"),&VisualScript::set_variable_export); + ObjectTypeDB::bind_method(_MD("get_variable_export","name"),&VisualScript::get_variable_export); ObjectTypeDB::bind_method(_MD("rename_variable","name","new_name"),&VisualScript::rename_variable); ObjectTypeDB::bind_method(_MD("add_custom_signal","name"),&VisualScript::add_custom_signal); @@ -1307,12 +1400,10 @@ 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); + Map<StringName,Variant>::Element *E=variables.find(p_name); + if (!E) + return false; E->get()=p_value; @@ -1322,35 +1413,29 @@ bool VisualScriptInstance::set(const StringName& p_name, const Variant& p_value) 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) + const Map<StringName,Variant>::Element *E=variables.find(p_name); + if (!E) return false; - const Map<StringName,Variant>::Element *E=variables.find(remap->get()); - ERR_FAIL_COND_V(!E,false); - - return E->get(); + r_ret=E->get(); + return true; } 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()) { + if (!E->get()._export) + continue; PropertyInfo p = E->get().info; - p.name=SCRIPT_VARIABLES_PREFIX+String(E->key()); + p.name=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()); + const Map<StringName,VisualScript::Variable>::Element *E=script->variables.find(p_name); if (!E) { if (r_is_valid) *r_is_valid=false; @@ -1400,7 +1485,59 @@ bool VisualScriptInstance::has_method(const StringName& p_method) const{ //#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) { +void VisualScriptInstance::_dependency_step(VisualScriptNodeInstance* node,int p_pass,int *pass_stack,const Variant **input_args,Variant **output_args,Variant *variant_stack,Variant::CallError& r_error,String& error_str,VisualScriptNodeInstance** r_error_node) { + + ERR_FAIL_COND(node->pass_idx==-1); + + if (pass_stack[node->pass_idx]==p_pass) + return; + + pass_stack[node->pass_idx]=p_pass; + + if (!node->dependencies.empty()) { + + int dc = node->dependencies.size(); + VisualScriptNodeInstance **deps=node->dependencies.ptr(); + + for(int i=0;i<dc;i++) { + + _dependency_step(deps[i],p_pass,pass_stack,input_args,output_args,variant_stack,r_error,error_str,r_error_node); + if (r_error.error!=Variant::CallError::CALL_OK) + return; + + } + } + + + 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]; + } else { + //regular temporary in stack + input_args[i]=&variant_stack[index]; + + } + } + for(int i=0 ; i<node->output_port_count ; i++) { + output_args[i] = &variant_stack[ node->output_ports[i] ]; + } + + Variant *working_mem=node->working_mem_idx>=0 ? &variant_stack[node->working_mem_idx] : (Variant*)NULL; + + node->step(input_args,output_args,VisualScriptNodeInstance::START_MODE_BEGIN_SEQUENCE,working_mem,r_error,error_str); + //ignore return + if (r_error.error!=Variant::CallError::CALL_OK) { + *r_error_node=node; + } + +} + +Variant VisualScriptInstance::_call_internal(const StringName& p_method, void* p_stack, int p_stack_size, VisualScriptNodeInstance* p_node, int p_flow_stack_pos, int p_pass, bool p_resuming_yield, Variant::CallError &r_error) { Map<StringName,Function>::Element *F = functions.find(p_method); ERR_FAIL_COND_V(!F,Variant()); @@ -1413,6 +1550,7 @@ Variant VisualScriptInstance::_call_internal(const StringName& p_method, void* p 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; + int *pass_stack = flow_stack + flow_max; String error_str; @@ -1432,6 +1570,7 @@ Variant VisualScriptInstance::_call_internal(const StringName& p_method, void* p while(true) { + p_pass++; //increment pass current_node_id=node->get_id(); VSDEBUG("==========AT NODE: "+itos(current_node_id)+" base: "+node->get_base_node()->get_type()); @@ -1450,38 +1589,46 @@ Variant VisualScriptInstance::_call_internal(const StringName& p_method, void* p 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++) { + //run dependencies first - int index = node->input_ports[i] & VisualScriptNodeInstance::INPUT_MASK; + if (!node->dependencies.empty()) { - 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]; + int dc = node->dependencies.size(); + VisualScriptNodeInstance **deps=node->dependencies.ptr(); - 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(); + for(int i=0;i<dc;i++) { + + _dependency_step(deps[i],p_pass,pass_stack,input_args,output_args,variant_stack,r_error,error_str,&node); + if (r_error.error!=Variant::CallError::CALL_OK) { error=true; - working_mem=NULL; + current_node_id=node->id; 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) { + //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 { + //regular temporary in stack + input_args[i]=&variant_stack[index]; + VSDEBUG("PORT "+itos(i)+" AT STACK "+itos(index)); + + } } } } @@ -1503,13 +1650,13 @@ Variant VisualScriptInstance::_call_internal(const StringName& p_method, void* p { 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 + 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)); + VSDEBUG("STEP - STARTSEQ: "+itos(start_mode)); int ret = node->step(input_args,output_args,start_mode,working_mem,r_error,error_str); @@ -1548,6 +1695,7 @@ Variant VisualScriptInstance::_call_internal(const StringName& p_method, void* p state->node=node; state->flow_stack_pos=flow_stack_pos; state->stack.resize(p_stack_size); + state->pass=p_pass; copymem(state->stack.ptr(),p_stack,p_stack_size); //step 2, run away, return directly r_error.error=Variant::CallError::CALL_OK; @@ -1718,6 +1866,7 @@ Variant VisualScriptInstance::_call_internal(const StringName& p_method, void* p node = instances[ flow_stack[i] & VisualScriptNodeInstance::FLOW_STACK_MASK ]; flow_stack_pos=i; found=true; + break; } } @@ -1746,6 +1895,26 @@ Variant VisualScriptInstance::_call_internal(const StringName& p_method, void* p String err_func = p_method; int err_line=current_node_id; //not a line but it works as one + if (node && (r_error.error!=Variant::CallError::CALL_ERROR_INVALID_METHOD || error_str==String())) { + + if (error_str!=String()) { + error_str+=" "; + } + + if (r_error.error==Variant::CallError::CALL_ERROR_INVALID_ARGUMENT) { + int errorarg=r_error.argument; + error_str+="Cannot convert argument "+itos(errorarg+1)+" to "+Variant::get_type_name(r_error.expected)+"."; + } else if (r_error.error==Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) { + error_str+="Expected "+itos(r_error.argument)+" arguments."; + } else if (r_error.error==Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) { + error_str+="Expected "+itos(r_error.argument)+" arguments."; + } else if (r_error.error==Variant::CallError::CALL_ERROR_INVALID_METHOD) { + error_str+="Invalid Call."; + } else if (r_error.error==Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL) { + error_str+="Base Instance is null"; + } + } + //if (!GDScriptLanguage::get_singleton()->debug_break(err_text,false)) { // debugger break did not happen @@ -1798,6 +1967,7 @@ Variant VisualScriptInstance::call(const StringName& p_method, const Variant** p 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 + total_stack_size+=f->pass_stack_size*sizeof(int); VSDEBUG("STACK SIZE: "+itos(total_stack_size)); VSDEBUG("STACK VARIANTS: : "+itos(f->max_stack)); @@ -1805,6 +1975,7 @@ Variant VisualScriptInstance::call(const StringName& p_method, const Variant** p VSDEBUG("MAX INPUT: "+itos(max_input_args)); VSDEBUG("MAX OUTPUT: "+itos(max_output_args)); VSDEBUG("FLOW STACK SIZE: "+itos(f->flow_stack_size)); + VSDEBUG("PASS STACK SIZE: "+itos(f->pass_stack_size)); void *stack = alloca(total_stack_size); @@ -1814,11 +1985,13 @@ Variant VisualScriptInstance::call(const StringName& p_method, const Variant** p 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; + int *pass_stack = flow_stack + flow_max; for(int i=0;i<f->node_count;i++) { sequence_bits[i]=false; //all starts as false } + zeromem(pass_stack,f->pass_stack_size*sizeof(int)); Map<int,VisualScriptNodeInstance*>::Element *E = instances.find(f->node); if (!E) { @@ -1861,7 +2034,7 @@ Variant VisualScriptInstance::call(const StringName& p_method, const Variant** p variant_stack[i]=*p_args[i]; } - return _call_internal(p_method,stack,total_stack_size,node,0,false,r_error); + return _call_internal(p_method,stack,total_stack_size,node,0,0,false,r_error); } @@ -1884,8 +2057,23 @@ Ref<Script> VisualScriptInstance::get_script() const{ ScriptInstance::RPCMode VisualScriptInstance::get_rpc_mode(const StringName& p_method) const { + const Map<StringName,VisualScript::Function>::Element *E = script->functions.find(p_method); + if (!E) { + return RPC_MODE_DISABLED; + } + + if (E->get().function_id>=0 && E->get().nodes.has(E->get().function_id)) { + + Ref<VisualScriptFunction> vsf = E->get().nodes[E->get().function_id].node; + if (vsf.is_valid()) { + + return vsf->get_rpc_mode(); + } + } + return RPC_MODE_DISABLED; } + ScriptInstance::RPCMode VisualScriptInstance::get_rset_mode(const StringName& p_variable) const { return RPC_MODE_DISABLED; @@ -1918,6 +2106,7 @@ void VisualScriptInstance::create(const Ref<VisualScript>& p_script,Object *p_ow for(const Map<StringName,VisualScript::Variable>::Element *E=script->variables.front();E;E=E->next()) { variables[E->key()]=E->get().default_value; + //no hacer que todo exporte, solo las que queres! } @@ -1927,7 +2116,9 @@ void VisualScriptInstance::create(const Ref<VisualScript>& p_script,Object *p_ow function.node=E->get().function_id; function.max_stack=0; function.flow_stack_size=0; + function.pass_stack_size=0; function.node_count=0; + Map<StringName,int> local_var_indices; if (function.node<0) { VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(),0,"No start node in function: "+String(E->key())); @@ -1966,15 +2157,20 @@ void VisualScriptInstance::create(const Ref<VisualScript>& p_script,Object *p_ow instance->id=F->key(); instance->input_port_count = node->get_input_value_port_count(); + instance->input_ports=NULL; instance->output_port_count = node->get_output_value_port_count(); + instance->output_ports=NULL; instance->sequence_output_count = node->get_output_sequence_port_count(); instance->sequence_index=function.node_count++; + instance->sequence_outputs=NULL; + instance->pass_idx=-1; 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) { @@ -1991,7 +2187,25 @@ void VisualScriptInstance::create(const Ref<VisualScript>& p_script,Object *p_ow } } - if (instance->get_working_memory_size()) { + if (node->cast_to<VisualScriptLocalVar>() || node->cast_to<VisualScriptLocalVarSet>()) { + //working memory is shared only for this node, for the same variables + Ref<VisualScriptLocalVar> vslv = node; + + StringName var_name; + + if (node->cast_to<VisualScriptLocalVar>()) + var_name = String(node->cast_to<VisualScriptLocalVar>()->get_var_name()).strip_edges(); + else + var_name = String(node->cast_to<VisualScriptLocalVarSet>()->get_var_name()).strip_edges(); + + if (!local_var_indices.has(var_name)) { + local_var_indices[var_name]=function.max_stack; + function.max_stack++; + } + + instance->working_mem_idx=local_var_indices[var_name]; + + } else if (instance->get_working_memory_size()) { instance->working_mem_idx = function.max_stack; function.max_stack+=instance->get_working_memory_size(); } else { @@ -2027,24 +2241,17 @@ void VisualScriptInstance::create(const Ref<VisualScript>& p_script,Object *p_ow } - 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 + if (from->get_sequence_output_count()==0 && to->dependencies.find(from)==-1) { + //if the node we are reading from has no output sequence, we must call step() before reading from it. + if (from->pass_idx==-1) { + from->pass_idx=function.pass_stack_size; + function.pass_stack_size++; + } + to->dependencies.push_back(from); } + to->input_ports[dc.to_port] = from->output_ports[dc.from_port]; //read from wherever the stack is + } //third pass, do sequence connections @@ -2179,7 +2386,7 @@ Variant VisualScriptFunctionState::_signal_callback(const Variant** p_args, int *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); + Variant ret = instance->_call_internal(function,stack.ptr(),stack.size(),node,flow_stack_pos,pass,true,r_error); function=StringName(); //invalidate return ret; } @@ -2221,7 +2428,7 @@ Variant VisualScriptFunctionState::resume(Array p_args) { *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); + Variant ret= instance->_call_internal(function,stack.ptr(),stack.size(),node,flow_stack_pos,pass,true,r_error); function=StringName(); //invalidate return ret; } @@ -2232,7 +2439,7 @@ 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")); + ObjectTypeDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"_signal_callback",&VisualScriptFunctionState::_signal_callback,MethodInfo("_signal_callback")); } VisualScriptFunctionState::VisualScriptFunctionState() { @@ -2424,7 +2631,7 @@ void VisualScriptLanguage::debug_get_stack_level_locals(int p_level,List<String> 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]; +// 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); @@ -2447,8 +2654,6 @@ void VisualScriptLanguage::debug_get_stack_level_locals(int p_level,List<String> 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] ); } @@ -2599,7 +2804,6 @@ 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; diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h index bad50c1cc8..63b018b0c2 100644 --- a/modules/visual_script/visual_script.h +++ b/modules/visual_script/visual_script.h @@ -20,6 +20,8 @@ friend class VisualScript; void _set_default_input_values(Array p_values); Array _get_default_input_values() const; + + void validate_input_default_values(); protected: virtual bool _use_builtin_script() const { return false; } @@ -36,6 +38,8 @@ public: virtual String get_output_sequence_port_text(int p_port) const=0; + virtual bool has_mixed_input_and_sequence_ports() const { return false; } + virtual int get_input_value_port_count() const=0; virtual int get_output_value_port_count() const=0; @@ -56,6 +60,18 @@ public: virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance)=0; + struct TypeGuess { + + Variant::Type type; + InputEvent::Type ev_type; + StringName obj_type; + Ref<Script> script; + + TypeGuess() { type=Variant::NIL; ev_type=InputEvent::NONE; } + }; + + virtual TypeGuess guess_output_type(TypeGuess* p_inputs, int p_output) const; + VisualScriptNode(); }; @@ -69,7 +85,6 @@ friend class VisualScriptLanguage; //for debugger 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). }; @@ -77,11 +92,13 @@ friend class VisualScriptLanguage; //for debugger int sequence_index; VisualScriptNodeInstance **sequence_outputs; int sequence_output_count; + Vector<VisualScriptNodeInstance*> dependencies; int *input_ports; int input_port_count; int *output_ports; int output_port_count; int working_mem_idx; + int pass_idx; VisualScriptNode *base; @@ -115,10 +132,6 @@ public: virtual int get_working_memory_size() const { return 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 ); } @@ -207,13 +220,13 @@ friend class VisualScriptInstance; struct Variable { PropertyInfo info; Variant default_value; + bool _export; }; Map<StringName,Function> functions; Map<StringName,Variable> variables; - Map<StringName,StringName> script_variable_remap; Map<StringName,Vector<Argument> > custom_signals; Map<Object*,VisualScriptInstance*> instances; @@ -267,14 +280,17 @@ public: bool has_data_connection(const StringName& p_func,int p_from_node,int p_from_port,int p_to_node,int p_to_port) const; void get_data_connection_list(const StringName& p_func,List<DataConnection> *r_connection) const; bool is_input_value_port_connected(const StringName& p_name,int p_node,int p_port) const; + bool get_input_value_port_connection_source(const StringName& p_name,int p_node,int p_port,int *r_node,int *r_port) const; - void add_variable(const StringName& p_name,const Variant& p_default_value=Variant()); + void add_variable(const StringName& p_name,const Variant& p_default_value=Variant(),bool p_export=false); bool has_variable(const StringName& p_name) const; void remove_variable(const StringName& p_name); void set_variable_default_value(const StringName& p_name,const Variant& p_value); Variant get_variable_default_value(const StringName& p_name) const; void set_variable_info(const StringName& p_name,const PropertyInfo& p_info); PropertyInfo get_variable_info(const StringName& p_name) const; + void set_variable_export(const StringName& p_name,bool p_export); + bool get_variable_export(const StringName& p_name) const; void get_variable_list(List<StringName> *r_variables) const; void rename_variable(const StringName& p_name,const StringName& p_new_name); @@ -300,6 +316,7 @@ public: virtual bool can_instance() const; + virtual Ref<Script> get_base_script() const; virtual StringName get_instance_base_type() const; virtual ScriptInstance* instance_create(Object *p_this); virtual bool instance_has(const Object *p_this) const; @@ -327,6 +344,9 @@ public: virtual void get_script_property_list(List<PropertyInfo> *p_list) const; +#ifdef TOOLS_ENABLED + virtual bool are_subnodes_edited() const; +#endif VisualScript(); ~VisualScript(); @@ -346,18 +366,10 @@ class VisualScriptInstance : public ScriptInstance { int trash_pos; int return_pos; int flow_stack_size; + int pass_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; @@ -367,7 +379,8 @@ class VisualScriptInstance : public ScriptInstance { 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); + void _dependency_step(VisualScriptNodeInstance* node, int p_pass, int *pass_stack, const Variant **input_args, Variant **output_args, Variant *variant_stack, Variant::CallError& r_error, String& error_str, VisualScriptNodeInstance **r_error_node); + Variant _call_internal(const StringName& p_method, void* p_stack,int p_stack_size, VisualScriptNodeInstance* p_node, int p_flow_stack_pos, int p_pass, bool p_resuming_yield,Variant::CallError &r_error); //Map<StringName,Function> functions; @@ -436,6 +449,7 @@ friend class VisualScriptInstance; int variant_stack_size; VisualScriptNodeInstance *node; int flow_stack_pos; + int pass; Variant _signal_callback(const Variant** p_args, int p_argcount, Variant::CallError& r_error); protected: diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp index e813d9ea84..24a44d3506 100644 --- a/modules/visual_script/visual_script_builtin_funcs.cpp +++ b/modules/visual_script/visual_script_builtin_funcs.cpp @@ -65,22 +65,48 @@ const char* VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX "bytes2var", }; +VisualScriptBuiltinFunc::BuiltinFunc VisualScriptBuiltinFunc::find_function(const String& p_string) { + + for(int i=0;i<FUNC_MAX;i++) { + if (p_string==func_name[i]) + return BuiltinFunc(i); + } + + return FUNC_MAX; +} + +String VisualScriptBuiltinFunc::get_func_name(BuiltinFunc p_func) { + + ERR_FAIL_INDEX_V(p_func,FUNC_MAX,String()); + return func_name[p_func]; +} int VisualScriptBuiltinFunc::get_output_sequence_port_count() const { - return 1; + return has_input_sequence_port() ? 1 : 0; } bool VisualScriptBuiltinFunc::has_input_sequence_port() const{ - return true; + switch(func) { + + case MATH_RANDOMIZE: + case TEXT_PRINT: + case TEXT_PRINTERR: + case TEXT_PRINTRAW: + return true; + default: + return false; + + } + } -int VisualScriptBuiltinFunc::get_input_value_port_count() const{ +int VisualScriptBuiltinFunc::get_func_argument_count(BuiltinFunc p_func) { - switch(func) { + switch(p_func) { case MATH_RANDOMIZE: case MATH_RAND: @@ -146,6 +172,11 @@ int VisualScriptBuiltinFunc::get_input_value_port_count() const{ } return 0; } + +int VisualScriptBuiltinFunc::get_input_value_port_count() const{ + + return get_func_argument_count(func); +} int VisualScriptBuiltinFunc::get_output_value_port_count() const{ switch(func) { @@ -549,118 +580,124 @@ VisualScriptBuiltinFunc::BuiltinFunc VisualScriptBuiltinFunc::get_func() { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;\ r_error.argument=m_arg;\ r_error.expected=Variant::REAL;\ - return 0;\ + return;\ } -class VisualScriptNodeInstanceBuiltinFunc : public VisualScriptNodeInstance { -public: - VisualScriptBuiltinFunc *node; - VisualScriptInstance *instance; +void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func,const Variant** p_inputs,Variant* r_return,Variant::CallError& r_error,String& r_error_str) { - VisualScriptBuiltinFunc::BuiltinFunc func; + switch(p_func) { + case VisualScriptBuiltinFunc::MATH_SIN: { + VALIDATE_ARG_NUM(0); + *r_return=Math::sin(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_COS: { - //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; } + VALIDATE_ARG_NUM(0); + *r_return=Math::cos(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_TAN: { - 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) { + VALIDATE_ARG_NUM(0); + *r_return=Math::tan(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_SINH: { - switch(func) { - case VisualScriptBuiltinFunc::MATH_SIN: { + VALIDATE_ARG_NUM(0); + *r_return=Math::sinh(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_COSH: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::sin(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_COS: { + VALIDATE_ARG_NUM(0); + *r_return=Math::cosh(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_TANH: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::cos(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_TAN: { + VALIDATE_ARG_NUM(0); + *r_return=Math::tanh(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ASIN: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::tan(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_SINH: { + VALIDATE_ARG_NUM(0); + *r_return=Math::asin(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ACOS: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::sinh(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_COSH: { + VALIDATE_ARG_NUM(0); + *r_return=Math::acos(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ATAN: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::cosh(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_TANH: { + VALIDATE_ARG_NUM(0); + *r_return=Math::atan(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ATAN2: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::tanh(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_ASIN: { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *r_return=Math::atan2(*p_inputs[0],*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_SQRT: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::asin(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_ACOS: { + VALIDATE_ARG_NUM(0); + *r_return=Math::sqrt(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_FMOD: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::acos(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_ATAN: { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *r_return=Math::fmod(*p_inputs[0],*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_FPOSMOD: { - 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); + *r_return=Math::fposmod(*p_inputs[0],*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_FLOOR: { - 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); + *r_return=Math::floor(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_CEIL: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::sqrt(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_FMOD: { + VALIDATE_ARG_NUM(0); + *r_return=Math::ceil(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ROUND: { - 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); + *r_return=Math::round(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ABS: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - *p_outputs[0]=Math::fposmod(*p_inputs[0],*p_inputs[1]); - } break; - case VisualScriptBuiltinFunc::MATH_FLOOR: { + if (p_inputs[0]->get_type()==Variant::INT) { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::floor(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_CEIL: { + int64_t i = *p_inputs[0]; + *r_return=ABS(i); + } else if (p_inputs[0]->get_type()==Variant::REAL) { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::ceil(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_ROUND: { + real_t r = *p_inputs[0]; + *r_return=Math::abs(r); + } else { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::round(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_ABS: { + 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]=ABS(i); + *r_return= 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]=Math::abs(r); + *r_return= r < 0.0 ? -1.0 : ( r > 0.0 ? +1.0 : 0.0); } else { r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; @@ -668,410 +705,412 @@ public: r_error.expected=Variant::REAL; } - } break; - case VisualScriptBuiltinFunc::MATH_SIGN: { + } break; + case VisualScriptBuiltinFunc::MATH_POW: { - if (p_inputs[0]->get_type()==Variant::INT) { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *r_return=Math::pow(*p_inputs[0],*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_LOG: { - 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) { + VALIDATE_ARG_NUM(0); + *r_return=Math::log(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_EXP: { - real_t r = *p_inputs[0]; - *p_outputs[0]= r < 0.0 ? -1.0 : ( r > 0.0 ? +1.0 : 0.0); - } else { + VALIDATE_ARG_NUM(0); + *r_return=Math::exp(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ISNAN: { - r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument=0; - r_error.expected=Variant::REAL; + VALIDATE_ARG_NUM(0); + *r_return=Math::is_nan(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_ISINF: { - } - } break; - case VisualScriptBuiltinFunc::MATH_POW: { + VALIDATE_ARG_NUM(0); + *r_return=Math::is_inf(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_EASE: { - 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); + VALIDATE_ARG_NUM(1); + *r_return=Math::ease(*p_inputs[0],*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_DECIMALS: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::log(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_EXP: { + VALIDATE_ARG_NUM(0); + *r_return=Math::step_decimals(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_STEPIFY: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::exp(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_ISNAN: { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *r_return=Math::stepify(*p_inputs[0],*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_LERP: { - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::is_nan(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_ISINF: { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); + *r_return=Math::lerp(*p_inputs[0],*p_inputs[1],*p_inputs[2]); + } break; + case VisualScriptBuiltinFunc::MATH_DECTIME: { - 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); + VALIDATE_ARG_NUM(2); + *r_return=Math::dectime(*p_inputs[0],*p_inputs[1],*p_inputs[2]); + } break; + case VisualScriptBuiltinFunc::MATH_RANDOMIZE: { + Math::randomize(); - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - *p_outputs[0]=Math::ease(*p_inputs[0],*p_inputs[1]); - } break; - case VisualScriptBuiltinFunc::MATH_DECIMALS: { + } break; + case VisualScriptBuiltinFunc::MATH_RAND: { + *r_return=Math::rand(); + } break; + case VisualScriptBuiltinFunc::MATH_RANDF: { + *r_return=Math::randf(); + } break; + case VisualScriptBuiltinFunc::MATH_RANDOM: { - 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); + *r_return=Math::random(*p_inputs[0],*p_inputs[1]); + } break; + case VisualScriptBuiltinFunc::MATH_SEED: { - 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); + uint32_t seed=*p_inputs[0]; + Math::seed(seed); - 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: { + } break; + case VisualScriptBuiltinFunc::MATH_RANDSEED: { - 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); + uint32_t seed=*p_inputs[0]; + int ret = Math::rand_from_seed(&seed); + Array reta; + reta.push_back(ret); + reta.push_back(seed); + *r_return=reta; - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - *p_outputs[0]=Math::random(*p_inputs[0],*p_inputs[1]); - } break; - case VisualScriptBuiltinFunc::MATH_SEED: { + } break; + case VisualScriptBuiltinFunc::MATH_DEG2RAD: { - VALIDATE_ARG_NUM(0); - uint32_t seed=*p_inputs[0]; - Math::seed(seed); + VALIDATE_ARG_NUM(0); + *r_return=Math::deg2rad(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_RAD2DEG: { + + VALIDATE_ARG_NUM(0); + *r_return=Math::rad2deg(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_LINEAR2DB: { - } break; - case VisualScriptBuiltinFunc::MATH_RANDSEED: { + VALIDATE_ARG_NUM(0); + *r_return=Math::linear2db(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::MATH_DB2LINEAR: { - 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; + VALIDATE_ARG_NUM(0); + *r_return=Math::db2linear(*p_inputs[0]); + } break; + case VisualScriptBuiltinFunc::LOGIC_MAX: { - } break; - case VisualScriptBuiltinFunc::MATH_DEG2RAD: { + 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]; + *r_return=MAX(a,b); + } else { VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::deg2rad(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_RAD2DEG: { + VALIDATE_ARG_NUM(1); - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::rad2deg(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_LINEAR2DB: { + real_t a = *p_inputs[0]; + real_t b = *p_inputs[1]; - VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::linear2db(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::MATH_DB2LINEAR: { + *r_return=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]; + *r_return=MIN(a,b); + } else { VALIDATE_ARG_NUM(0); - *p_outputs[0]=Math::db2linear(*p_inputs[0]); - } break; - case VisualScriptBuiltinFunc::LOGIC_MAX: { + VALIDATE_ARG_NUM(1); - if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT) { + real_t a = *p_inputs[0]; + real_t b = *p_inputs[1]; - 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); + *r_return=MIN(a,b); + } + } break; + case VisualScriptBuiltinFunc::LOGIC_CLAMP: { - real_t a = *p_inputs[0]; - real_t b = *p_inputs[1]; + if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT && p_inputs[2]->get_type()==Variant::INT) { - *p_outputs[0]=MAX(a,b); - } + int64_t a = *p_inputs[0]; + int64_t b = *p_inputs[1]; + int64_t c = *p_inputs[2]; + *r_return=CLAMP(a,b,c); + } else { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); - } break; - case VisualScriptBuiltinFunc::LOGIC_MIN: { + real_t a = *p_inputs[0]; + real_t b = *p_inputs[1]; + real_t c = *p_inputs[2]; - if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT) { + *r_return=CLAMP(a,b,c); + } + } break; + case VisualScriptBuiltinFunc::LOGIC_NEAREST_PO2: { - 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); + VALIDATE_ARG_NUM(0); + int64_t num = *p_inputs[0]; + *r_return = nearest_power_of_2(num); + } break; + case VisualScriptBuiltinFunc::OBJ_WEAKREF: { - real_t a = *p_inputs[0]; - real_t b = *p_inputs[1]; + if (p_inputs[0]->get_type()!=Variant::OBJECT) { - *p_outputs[0]=MIN(a,b); - } - } break; - case VisualScriptBuiltinFunc::LOGIC_CLAMP: { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::OBJECT; - if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT && p_inputs[2]->get_type()==Variant::INT) { + return; - 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); + } + + if (p_inputs[0]->is_ref()) { - real_t a = *p_inputs[0]; - real_t b = *p_inputs[1]; - real_t c = *p_inputs[2]; + REF r = *p_inputs[0]; + if (!r.is_valid()) { - *p_outputs[0]=CLAMP(a,b,c); + return; } - } 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: { + Ref<WeakRef> wref = memnew( WeakRef ); + wref->set_ref(r); + *r_return=wref; + } else { + Object *obj = *p_inputs[0]; + if (!obj) { - if (p_inputs[0]->get_type()!=Variant::OBJECT) { + return; + } + Ref<WeakRef> wref = memnew( WeakRef ); + wref->set_obj(obj); + *r_return=wref; + } - 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()) { + } break; + case VisualScriptBuiltinFunc::FUNC_FUNCREF: { - REF r = *p_inputs[0]; - if (!r.is_valid()) { + if (p_inputs[0]->get_type()!=Variant::OBJECT) { - return 0; - } + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::OBJECT; - 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; - } + return; + } + 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; - } break; - case VisualScriptBuiltinFunc::FUNC_FUNCREF: { + } - if (p_inputs[0]->get_type()!=Variant::OBJECT) { + Ref<FuncRef> fr = memnew( FuncRef); - r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument=0; - r_error.expected=Variant::OBJECT; + fr->set_instance(*p_inputs[0]); + fr->set_function(*p_inputs[1]); - return 0; + *r_return=fr; - } - if (p_inputs[1]->get_type()!=Variant::STRING && p_inputs[1]->get_type()!=Variant::NODE_PATH) { + } break; + case VisualScriptBuiltinFunc::TYPE_CONVERT: { - r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument=1; - r_error.expected=Variant::STRING; + VALIDATE_ARG_NUM(1); + int type=*p_inputs[1]; + if (type<0 || type>=Variant::VARIANT_MAX) { - return 0; + r_error_str=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; + + } else { - } - Ref<FuncRef> fr = memnew( FuncRef); + *r_return=Variant::construct(Variant::Type(type),p_inputs,1,r_error); + } + } break; + case VisualScriptBuiltinFunc::TYPE_OF: { - fr->set_instance(*p_inputs[0]); - fr->set_function(*p_inputs[1]); - *p_outputs[0]=fr; + *r_return = p_inputs[0]->get_type(); - } break; - case VisualScriptBuiltinFunc::TYPE_CONVERT: { + } break; + case VisualScriptBuiltinFunc::TYPE_EXISTS: { - 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; + *r_return = ObjectTypeDB::type_exists(*p_inputs[0]); - } else { + } break; + case VisualScriptBuiltinFunc::TEXT_STR: { + String str = *p_inputs[0]; - *p_outputs[0]=Variant::construct(Variant::Type(type),p_inputs,1,r_error); - } - } break; - case VisualScriptBuiltinFunc::TYPE_OF: { + *r_return=str; + } break; + case VisualScriptBuiltinFunc::TEXT_PRINT: { - *p_outputs[0] = p_inputs[0]->get_type(); + String str = *p_inputs[0]; + print_line(str); - } break; - case VisualScriptBuiltinFunc::TYPE_EXISTS: { + } break; - *p_outputs[0] = ObjectTypeDB::type_exists(*p_inputs[0]); + case VisualScriptBuiltinFunc::TEXT_PRINTERR: { - } break; - case VisualScriptBuiltinFunc::TEXT_STR: { + String str = *p_inputs[0]; - String str = *p_inputs[0]; + //str+="\n"; + OS::get_singleton()->printerr("%s\n",str.utf8().get_data()); - *p_outputs[0]=str; - } break; - case VisualScriptBuiltinFunc::TEXT_PRINT: { + } break; + case VisualScriptBuiltinFunc::TEXT_PRINTRAW: { + String str = *p_inputs[0]; - String str = *p_inputs[0]; - print_line(str); + //str+="\n"; + OS::get_singleton()->print("%s",str.utf8().get_data()); - } break; + } break; + case VisualScriptBuiltinFunc::VAR_TO_STR: { - case VisualScriptBuiltinFunc::TEXT_PRINTERR: { + String vars; + VariantWriter::write_to_string(*p_inputs[0],vars); + *r_return=vars; + } break; + case VisualScriptBuiltinFunc::STR_TO_VAR: { - String str = *p_inputs[0]; + 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; - //str+="\n"; - OS::get_singleton()->printerr("%s\n",str.utf8().get_data()); + return; + } + VariantParser::StreamString ss; + ss.s=*p_inputs[0]; - } break; - case VisualScriptBuiltinFunc::TEXT_PRINTRAW: { - String str = *p_inputs[0]; + String errs; + int line; + Error err = VariantParser::parse(&ss,*r_return,errs,line); - //str+="\n"; - OS::get_singleton()->print("%s",str.utf8().get_data()); + if (err!=OK) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::STRING; + *r_return="Parse error at line "+itos(line)+": "+errs; + return; + } + } break; + case VisualScriptBuiltinFunc::VAR_TO_BYTES: { - } 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: { + 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; + r_error_str="Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID)."; + return; + } - 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; + barr.resize(len); + { + ByteArray::Write w = barr.write(); + encode_variant(*p_inputs[0],w.ptr(),len); - return 0; - } + } + *r_return=barr; + } break; + case VisualScriptBuiltinFunc::BYTES_TO_VAR: { - VariantParser::StreamString ss; - ss.s=*p_inputs[0]; + 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; - String errs; - int line; - Error err = VariantParser::parse(&ss,*p_outputs[0],errs,line); + return; + } + 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) { + r_error_str=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::STRING; - *p_outputs[0]="Parse error at line "+itos(line)+": "+errs; - return 0; + r_error.expected=Variant::RAW_ARRAY; + return; } - } break; - case VisualScriptBuiltinFunc::VAR_TO_BYTES: { + } + *r_return=ret; - 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; - } + } break; + default: {} + } - 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; +class VisualScriptNodeInstanceBuiltinFunc : public VisualScriptNodeInstance { +public: - return 0; - } + VisualScriptBuiltinFunc *node; + VisualScriptInstance *instance; - 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; - } + VisualScriptBuiltinFunc::BuiltinFunc func; - } - *p_outputs[0]=ret; + //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) { - } break; - default: {} - } + VisualScriptBuiltinFunc::exec_func(func,p_inputs,p_outputs[0],r_error,r_error_str); return 0; } diff --git a/modules/visual_script/visual_script_builtin_funcs.h b/modules/visual_script/visual_script_builtin_funcs.h index ebf227a192..000230d84f 100644 --- a/modules/visual_script/visual_script_builtin_funcs.h +++ b/modules/visual_script/visual_script_builtin_funcs.h @@ -68,6 +68,11 @@ public: FUNC_MAX }; + static int get_func_argument_count(BuiltinFunc p_func); + static String get_func_name(BuiltinFunc p_func); + static void exec_func(BuiltinFunc p_func, const Variant** p_inputs, Variant* r_return, Variant::CallError& r_error, String& r_error_str); + static BuiltinFunc find_function(const String& p_string); + private: static const char* func_name[FUNC_MAX]; BuiltinFunc func; diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index 3424395d3f..76f6f47ad8 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/modules/visual_script/visual_script_editor.cpp @@ -3,7 +3,9 @@ #include "visual_script_nodes.h" #include "visual_script_flow_control.h" #include "visual_script_func_nodes.h" +#include "visual_script_expression.h" #include "os/input.h" +#include "tools/editor/editor_resource_preview.h" #include "os/keyboard.h" #ifdef TOOLS_ENABLED @@ -241,6 +243,11 @@ protected: return true; } + if (String(p_name)=="export") { + script->set_variable_export(var,p_value); + return true; + } + return false; } @@ -270,6 +277,11 @@ protected: return true; } + if (String(p_name)=="export") { + r_ret=script->get_variable_export(var); + return true; + } + return false; } void _get_property_list( List<PropertyInfo> *p_list) const { @@ -285,6 +297,7 @@ protected: p_list->push_back(PropertyInfo(script->get_variable_info(var).type,"value",script->get_variable_info(var).hint,script->get_variable_info(var).hint_string,PROPERTY_USAGE_DEFAULT)); p_list->push_back(PropertyInfo(Variant::INT,"hint",PROPERTY_HINT_ENUM,"None,Range,ExpRange,Enum,ExpEasing,Length,SpriteFrame,KeyAccel,BitFlags,AllFlags,File,Dir,GlobalFile,GlobalDir,ResourceType,MultilineText")); p_list->push_back(PropertyInfo(Variant::STRING,"hint_string")); + p_list->push_back(PropertyInfo(Variant::BOOL,"export")); } @@ -301,9 +314,45 @@ public: }; static Color _color_from_type(Variant::Type p_type) { - Color color; - color.set_hsv(p_type/float(Variant::VARIANT_MAX),0.7,0.7); + switch(p_type) { + case Variant::NIL: color = Color::html("69ecbd"); break; + + case Variant::BOOL: color = Color::html("8da6f0"); break; + case Variant::INT: color = Color::html("7dc6ef"); break; + case Variant::REAL: color = Color::html("61daf4"); break; + case Variant::STRING: color = Color::html("6ba7ec"); break; + + case Variant::VECTOR2: color = Color::html("bd91f1"); break; + case Variant::RECT2: color = Color::html("f191a5"); break; + case Variant::VECTOR3: color = Color::html("d67dee"); break; + case Variant::MATRIX32: color = Color::html("c4ec69"); break; + case Variant::PLANE: color = Color::html("f77070"); break; + case Variant::QUAT: color = Color::html("ec69a3"); break; + case Variant::_AABB: color = Color::html("ee7991"); break; + case Variant::MATRIX3: color = Color::html("e3ec69"); break; + case Variant::TRANSFORM: color = Color::html("f6a86e"); break; + + case Variant::COLOR: color = Color::html("9dff70"); break; + case Variant::IMAGE: color = Color::html("93f1b9"); break; + case Variant::NODE_PATH: color = Color::html("6993ec"); break; + case Variant::_RID: color = Color::html("69ec9a"); break; + case Variant::OBJECT: color = Color::html("79f3e8"); break; + case Variant::INPUT_EVENT: color = Color::html("adf18f"); break; + case Variant::DICTIONARY: color = Color::html("77edb1"); break; + + case Variant::ARRAY: color = Color::html("e0e0e0"); break; + case Variant::RAW_ARRAY: color = Color::html("aaf4c8"); break; + case Variant::INT_ARRAY: color = Color::html("afdcf5"); break; + case Variant::REAL_ARRAY: color = Color::html("97e7f8"); break; + case Variant::STRING_ARRAY: color = Color::html("9dc4f2"); break; + case Variant::VECTOR2_ARRAY: color = Color::html("d1b3f5"); break; + case Variant::VECTOR3_ARRAY: color = Color::html("df9bf2"); break; + case Variant::COLOR_ARRAY: color = Color::html("e9ff97"); break; + + default: + color.set_hsv(p_type/float(Variant::VARIANT_MAX),0.7,0.7); + } return color; } @@ -347,6 +396,8 @@ void VisualScriptEditor::_update_graph_connections() { void VisualScriptEditor::_update_graph(int p_only_id) { + if (updating_graph) + return; updating_graph=true; @@ -387,7 +438,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) { Control::get_icon("MiniVector2","EditorIcons"), Control::get_icon("MiniRect2","EditorIcons"), Control::get_icon("MiniVector3","EditorIcons"), - Control::get_icon("MiniMatrix2","EditorIcons"), + Control::get_icon("MiniMatrix32","EditorIcons"), Control::get_icon("MiniPlane","EditorIcons"), Control::get_icon("MiniQuat","EditorIcons"), Control::get_icon("MiniAabb","EditorIcons"), @@ -451,9 +502,31 @@ void VisualScriptEditor::_update_graph(int p_only_id) { gnode->set_show_close_button(true); } - Label *text = memnew( Label ); - text->set_text(node->get_text()); - gnode->add_child(text); + + if (node->cast_to<VisualScriptExpression>()) { + + LineEdit *line_edit = memnew( LineEdit ); + line_edit->set_text(node->get_text()); + line_edit->set_expand_to_text_length(true); + line_edit->add_font_override("font",get_font("source","EditorFonts")); + gnode->add_child(line_edit); + line_edit->connect("text_changed",this,"_expression_text_changed",varray(E->get())); + } else { + Label *text = memnew( Label ); + text->set_text(node->get_text()); + gnode->add_child(text); + } + + + if (node->cast_to<VisualScriptComment>()) { + Ref<VisualScriptComment> vsc=node; + gnode->set_comment(true); + gnode->set_resizeable(true); + gnode->set_custom_minimum_size(vsc->get_size()*EDSCALE); + gnode->connect("resize_request",this,"_comment_node_resized",varray(E->get())); + + } + int slot_idx=0; @@ -462,24 +535,34 @@ void VisualScriptEditor::_update_graph(int p_only_id) { gnode->set_offset(pos*EDSCALE); slot_idx++; + + int mixed_seq_ports=0; + if (!single_seq_output) { - for(int i=0;i<node->get_output_sequence_port_count();i++) { - Label *text2 = memnew( Label ); - text2->set_text(node->get_output_sequence_port_text(i)); - text2->set_align(Label::ALIGN_RIGHT); - gnode->add_child(text2); - gnode->set_slot(slot_idx,false,0,Color(),true,TYPE_SEQUENCE,Color(1,1,1,1),seq_port,seq_port); - slot_idx++; + if (node->has_mixed_input_and_sequence_ports()) { + mixed_seq_ports=node->get_output_sequence_port_count(); + } else { + for(int i=0;i<node->get_output_sequence_port_count();i++) { + + Label *text2 = memnew( Label ); + text2->set_text(node->get_output_sequence_port_text(i)); + text2->set_align(Label::ALIGN_RIGHT); + gnode->add_child(text2); + gnode->set_slot(slot_idx,false,0,Color(),true,TYPE_SEQUENCE,Color(1,1,1,1),seq_port,seq_port); + slot_idx++; + } } } - for(int i=0;i<MAX(node->get_output_value_port_count(),node->get_input_value_port_count());i++) { + for(int i=0;i<MAX(node->get_output_value_port_count(),MAX(mixed_seq_ports,node->get_input_value_port_count()));i++) { bool left_ok=false; Variant::Type left_type=Variant::NIL; String left_name; + + if (i<node->get_input_value_port_count()) { PropertyInfo pi = node->get_input_value_port_info(i); left_ok=true; @@ -491,8 +574,8 @@ void VisualScriptEditor::_update_graph(int p_only_id) { Variant::Type right_type=Variant::NIL; String right_name; - if (i<node->get_output_value_port_count()) { - PropertyInfo pi = node->get_output_value_port_info(i); + if (i>=mixed_seq_ports && i<node->get_output_value_port_count()+mixed_seq_ports) { + PropertyInfo pi = node->get_output_value_port_info(i-mixed_seq_ports); right_ok=true; right_type=pi.type; right_name=pi.name; @@ -516,6 +599,8 @@ void VisualScriptEditor::_update_graph(int p_only_id) { hbc->add_child(memnew(Label(left_name))); if (left_type!=Variant::NIL && !script->is_input_value_port_connected(edited_func,E->get(),i)) { + + PropertyInfo pi = node->get_input_value_port_info(i); Button *button = memnew( Button ); Variant value = node->get_default_input_value(i); if (value.get_type()!=left_type) { @@ -526,7 +611,24 @@ void VisualScriptEditor::_update_graph(int p_only_id) { value = Variant::construct(left_type,&existingp,1,ce,false); } - button->set_text(value); + if (left_type==Variant::COLOR) { + button->set_custom_minimum_size(Size2(30,0)*EDSCALE); + button->connect("draw",this,"_draw_color_over_button",varray(button,value)); + } else if (left_type==Variant::OBJECT && Ref<Resource>(value).is_valid()) { + + Ref<Resource> res = value; + Array arr; + arr.push_back(button->get_instance_ID()); + arr.push_back(String(value)); + EditorResourcePreview::get_singleton()->queue_edited_resource_preview(res,this,"_button_resource_previewed",arr); + + } else if (pi.type==Variant::INT && pi.hint==PROPERTY_HINT_ENUM){ + + button->set_text(pi.hint_string.get_slice(",",value)); + } else { + + button->set_text(value); + } button->connect("pressed",this,"_default_value_edited",varray(button,E->get(),i)); hbc->add_child(button); } @@ -538,6 +640,14 @@ void VisualScriptEditor::_update_graph(int p_only_id) { hbc->add_spacer(); + if (i<mixed_seq_ports) { + + Label *text2 = memnew( Label ); + text2->set_text(node->get_output_sequence_port_text(i)); + text2->set_align(Label::ALIGN_RIGHT); + hbc->add_child(text2); + } + if (right_ok) { hbc->add_child(memnew(Label(right_name))); @@ -557,12 +667,20 @@ void VisualScriptEditor::_update_graph(int p_only_id) { gnode->add_child(hbc); - gnode->set_slot(slot_idx,left_ok,left_type,_color_from_type(left_type),right_ok,right_type,_color_from_type(right_type)); + if (i<mixed_seq_ports) { + gnode->set_slot(slot_idx,left_ok,left_type,_color_from_type(left_type),true,TYPE_SEQUENCE,Color(1,1,1,1),Ref<Texture>(),seq_port); + } else { + gnode->set_slot(slot_idx,left_ok,left_type,_color_from_type(left_type),right_ok,right_type,_color_from_type(right_type)); + } slot_idx++; } graph->add_child(gnode); + + if (gnode->is_comment()) { + graph->move_child(gnode,0); + } } _update_graph_connections(); @@ -610,12 +728,48 @@ void VisualScriptEditor::_update_members() { variables->add_button(0,Control::get_icon("Add","EditorIcons")); variables->set_custom_bg_color(0,Control::get_color("prop_section","Editor")); + Ref<Texture> type_icons[Variant::VARIANT_MAX]={ + Control::get_icon("MiniVariant","EditorIcons"), + Control::get_icon("MiniBoolean","EditorIcons"), + Control::get_icon("MiniInteger","EditorIcons"), + Control::get_icon("MiniFloat","EditorIcons"), + Control::get_icon("MiniString","EditorIcons"), + Control::get_icon("MiniVector2","EditorIcons"), + Control::get_icon("MiniRect2","EditorIcons"), + Control::get_icon("MiniVector3","EditorIcons"), + Control::get_icon("MiniMatrix32","EditorIcons"), + Control::get_icon("MiniPlane","EditorIcons"), + Control::get_icon("MiniQuat","EditorIcons"), + Control::get_icon("MiniAabb","EditorIcons"), + Control::get_icon("MiniMatrix3","EditorIcons"), + Control::get_icon("MiniTransform","EditorIcons"), + Control::get_icon("MiniColor","EditorIcons"), + Control::get_icon("MiniImage","EditorIcons"), + Control::get_icon("MiniPath","EditorIcons"), + Control::get_icon("MiniRid","EditorIcons"), + Control::get_icon("MiniObject","EditorIcons"), + Control::get_icon("MiniInput","EditorIcons"), + Control::get_icon("MiniDictionary","EditorIcons"), + Control::get_icon("MiniArray","EditorIcons"), + Control::get_icon("MiniRawArray","EditorIcons"), + Control::get_icon("MiniIntArray","EditorIcons"), + Control::get_icon("MiniFloatArray","EditorIcons"), + Control::get_icon("MiniStringArray","EditorIcons"), + Control::get_icon("MiniVector2Array","EditorIcons"), + Control::get_icon("MiniVector3Array","EditorIcons"), + Control::get_icon("MiniColorArray","EditorIcons") + }; List<StringName> var_names; script->get_variable_list(&var_names); for (List<StringName>::Element *E=var_names.front();E;E=E->next()) { TreeItem *ti = members->create_item(variables); + ti->set_text(0,E->get()); + Variant var = script->get_variable_default_value(E->get()); + ti->set_suffix(0,"="+String(var)); + ti->set_icon(0,type_icons[script->get_variable_info(E->get()).type]); + ti->set_selectable(0,true); ti->set_editable(0,true); ti->add_button(0,Control::get_icon("Edit","EditorIcons"),0); @@ -1055,6 +1209,30 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt } } +void VisualScriptEditor::_expression_text_changed(const String& p_text,int p_id) { + + Ref<VisualScriptExpression> vse = script->get_node(edited_func,p_id); + if (!vse.is_valid()) + return; + + + updating_graph=true; + + undo_redo->create_action(TTR("Change Expression"),UndoRedo::MERGE_ENDS); + undo_redo->add_do_property(vse.ptr(),"expression",p_text); + undo_redo->add_undo_property(vse.ptr(),"expression",vse->get("expression")); + undo_redo->add_do_method(this,"_update_graph",p_id); + undo_redo->add_undo_method(this,"_update_graph",p_id); + undo_redo->commit_action(); + + Node *node = graph->get_node(itos(p_id)); + if (node->cast_to<Control>()) + node->cast_to<Control>()->set_size(Vector2(1,1)); //shrink if text is smaller + + updating_graph=false; + +} + void VisualScriptEditor::_available_node_doubleclicked() { TreeItem *item = nodes->get_selected(); @@ -1387,6 +1565,8 @@ bool VisualScriptEditor::can_drop_data_fw(const Point2& p_point,const Variant& p String(d["type"])=="visual_script_variable_drag" || String(d["type"])=="visual_script_signal_drag" || String(d["type"])=="obj_property" || + String(d["type"])=="resource" || + String(d["type"])=="files" || String(d["type"])=="nodes" ) ) { @@ -1394,18 +1574,27 @@ bool VisualScriptEditor::can_drop_data_fw(const Point2& p_point,const Variant& p if (String(d["type"])=="obj_property") { #ifdef OSX_ENABLED - const_cast<VisualScriptEditor*>(this)->_show_hint("Hold Meta to drop a Setter, Shift+Meta to drop a Setter and copy the value."); + const_cast<VisualScriptEditor*>(this)->_show_hint(TTR("Hold Meta to drop a Getter. Hold Shift to drop a generic signature.")); +#else + const_cast<VisualScriptEditor*>(this)->_show_hint(TTR("Hold Ctrl to drop a Getter. Hold Shift to drop a generic signature.")); +#endif + } + + if (String(d["type"])=="nodes") { + +#ifdef OSX_ENABLED + const_cast<VisualScriptEditor*>(this)->_show_hint(TTR("Hold Meta to drop a simple reference to the node.")); #else - const_cast<VisualScriptEditor*>(this)->_show_hint("Hold Ctrl to drop a Setter, Shift+Ctrl to drop a Setter and copy the value."); + const_cast<VisualScriptEditor*>(this)->_show_hint(TTR("Hold Ctrl to drop a simple reference to the node.")); #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."); + const_cast<VisualScriptEditor*>(this)->_show_hint(TTR("Hold Meta to drop a Variable Setter.")); #else - const_cast<VisualScriptEditor*>(this)->_show_hint("Hold Ctrl to drop a Variable Setter."); + const_cast<VisualScriptEditor*>(this)->_show_hint(TTR("Hold Ctrl to drop a Variable Setter.")); #endif } @@ -1444,6 +1633,8 @@ static Node* _find_script_node(Node* p_edited_scene,Node* p_current_node,const R #endif + + void VisualScriptEditor::drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from){ if (p_from==graph) { @@ -1532,16 +1723,18 @@ void VisualScriptEditor::drop_data_fw(const Point2& p_point,const Variant& p_dat } ofs/=EDSCALE; -#if 0 - Ref<VisualScriptScriptCall> vnode; + + Ref<VisualScriptFunctionCall> vnode; vnode.instance(); - vnode->set_call_mode(VisualScriptScriptCall::CALL_MODE_SELF); - vnode->set_function(d["function"]); + vnode->set_call_mode(VisualScriptFunctionCall::CALL_MODE_SELF); int new_id = script->get_available_id(); undo_redo->create_action(TTR("Add Node")); undo_redo->add_do_method(script.ptr(),"add_node",edited_func,new_id,vnode,ofs); + undo_redo->add_do_method(vnode.ptr(),"set_base_type",script->get_instance_base_type()); + undo_redo->add_do_method(vnode.ptr(),"set_function",d["function"]); + undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id); undo_redo->add_do_method(this,"_update_graph"); undo_redo->add_undo_method(this,"_update_graph"); @@ -1552,7 +1745,7 @@ void VisualScriptEditor::drop_data_fw(const Point2& p_point,const Variant& p_dat graph->set_selected(node); _node_selected(node); } -#endif + } @@ -1583,8 +1776,90 @@ void VisualScriptEditor::drop_data_fw(const Point2& p_point,const Variant& p_dat if (node) { graph->set_selected(node); _node_selected(node); + } + } + + if (d.has("type") && String(d["type"])=="resource") { + + Vector2 ofs = graph->get_scroll_ofs() + p_point; + if (graph->is_using_snap()) { + int snap = graph->get_snap(); + ofs = ofs.snapped(Vector2(snap,snap)); + } + + ofs/=EDSCALE; + + Ref<VisualScriptPreload> prnode; + prnode.instance(); + prnode->set_preload(d["resource"]); + + int new_id = script->get_available_id(); + + undo_redo->create_action(TTR("Add Preload Node")); + undo_redo->add_do_method(script.ptr(),"add_node",edited_func,new_id,prnode,ofs); + undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id); + undo_redo->add_do_method(this,"_update_graph"); + undo_redo->add_undo_method(this,"_update_graph"); + undo_redo->commit_action(); + + Node* node = graph->get_node(itos(new_id)); + if (node) { + graph->set_selected(node); + _node_selected(node); } } + + if (d.has("type") && String(d["type"])=="files") { + + Vector2 ofs = graph->get_scroll_ofs() + p_point; + if (graph->is_using_snap()) { + int snap = graph->get_snap(); + ofs = ofs.snapped(Vector2(snap,snap)); + } + + ofs/=EDSCALE; + + Array files = d["files"]; + + List<int> new_ids; + int new_id = script->get_available_id(); + + if (files.size()) { + undo_redo->create_action(TTR("Add Preload Node")); + + for(int i=0;i<files.size();i++) { + + Ref<Resource> res = ResourceLoader::load(files[i]); + if (!res.is_valid()) + continue; + + Ref<VisualScriptPreload> prnode; + prnode.instance(); + prnode->set_preload(res); + + undo_redo->add_do_method(script.ptr(),"add_node",edited_func,new_id,prnode,ofs); + undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id); + new_ids.push_back(new_id); + new_id++; + ofs+=Vector2(20,20)*EDSCALE; + } + + + undo_redo->add_do_method(this,"_update_graph"); + undo_redo->add_undo_method(this,"_update_graph"); + undo_redo->commit_action(); + } + + for(List<int>::Element *E=new_ids.front();E;E=E->next()) { + + Node* node = graph->get_node(itos(E->get())); + if (node) { + graph->set_selected(node); + _node_selected(node); + } + } + } + if (d.has("type") && String(d["type"])=="nodes") { Node* sn = _find_script_node(get_tree()->get_edited_scene_root(),get_tree()->get_edited_scene_root(),script); @@ -1595,6 +1870,14 @@ void VisualScriptEditor::drop_data_fw(const Point2& p_point,const Variant& p_dat return; } + +#ifdef OSX_ENABLED + bool use_node = Input::get_singleton()->is_key_pressed(KEY_META); +#else + bool use_node = Input::get_singleton()->is_key_pressed(KEY_CONTROL); +#endif + + Array nodes = d["nodes"]; Vector2 ofs = graph->get_scroll_ofs() + p_point; @@ -1608,6 +1891,10 @@ void VisualScriptEditor::drop_data_fw(const Point2& p_point,const Variant& p_dat undo_redo->create_action(TTR("Add Node(s) From Tree")); int base_id = script->get_available_id(); + if (nodes.size()>1) { + use_node=true; + } + for(int i=0;i<nodes.size();i++) { NodePath np = nodes[i]; @@ -1616,10 +1903,30 @@ void VisualScriptEditor::drop_data_fw(const Point2& p_point,const Variant& p_dat continue; } - Ref<VisualScriptSceneNode> scene_node; - scene_node.instance(); - scene_node->set_node_path(sn->get_path_to(node)); - undo_redo->add_do_method(script.ptr(),"add_node",edited_func,base_id,scene_node,ofs); + Ref<VisualScriptNode> n; + + if (use_node) { + Ref<VisualScriptSceneNode> scene_node; + scene_node.instance(); + scene_node->set_node_path(sn->get_path_to(node)); + n=scene_node; + + + } else { + Ref<VisualScriptFunctionCall> call; + call.instance(); + call->set_call_mode(VisualScriptFunctionCall::CALL_MODE_NODE_PATH); + call->set_base_path(sn->get_path_to(node));; + call->set_base_type(node->get_type()); + n=call; + + method_select->select_method_from_instance(node); + selecting_method_id=base_id; + + } + + + undo_redo->add_do_method(script.ptr(),"add_node",edited_func,base_id,n,ofs); undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,base_id); base_id++; @@ -1637,9 +1944,9 @@ void VisualScriptEditor::drop_data_fw(const Point2& p_point,const Variant& p_dat Node* sn = _find_script_node(get_tree()->get_edited_scene_root(),get_tree()->get_edited_scene_root(),script); - if (!sn) { - //EditorNode::get_singleton()->show_warning("Can't drop properties because script '"+get_name()+"' is not used in this scene."); - //return; + if (!sn && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { + EditorNode::get_singleton()->show_warning("Can't drop properties because script '"+get_name()+"' is not used in this scene.\nDrop holding 'Shift' to just copy the signature."); + return; } Object *obj=d["object"]; @@ -1657,36 +1964,33 @@ void VisualScriptEditor::drop_data_fw(const Point2& p_point,const Variant& p_dat ofs/=EDSCALE; #ifdef OSX_ENABLED - bool use_set = Input::get_singleton()->is_key_pressed(KEY_META); + bool use_get = Input::get_singleton()->is_key_pressed(KEY_META); #else - bool use_set = Input::get_singleton()->is_key_pressed(KEY_CONTROL); + bool use_get = Input::get_singleton()->is_key_pressed(KEY_CONTROL); #endif - bool use_value = Input::get_singleton()->is_key_pressed(KEY_SHIFT); + if (!node || Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { - if (!node) { - - if (use_set) - undo_redo->create_action(TTR("Add Setter Property")); - else + if (use_get) undo_redo->create_action(TTR("Add Getter Property")); + else + undo_redo->create_action(TTR("Add Setter Property")); int base_id = script->get_available_id(); Ref<VisualScriptNode> vnode; - if (use_set) { + if (!use_get) { Ref<VisualScriptPropertySet> pset; pset.instance(); pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE); pset->set_base_type(obj->get_type()); - pset->set_property(d["property"]); - if (use_value) { + /*if (use_value) { pset->set_use_builtin_value(true); pset->set_builtin_value(d["value"]); - } + }*/ vnode=pset; } else { @@ -1694,12 +1998,17 @@ void VisualScriptEditor::drop_data_fw(const Point2& p_point,const Variant& p_dat pget.instance(); pget->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE); pget->set_base_type(obj->get_type()); - pget->set_property(d["property"]); + vnode=pget; } undo_redo->add_do_method(script.ptr(),"add_node",edited_func,base_id,vnode,ofs); + undo_redo->add_do_method(vnode.ptr(),"set_property",d["property"]); + if (!use_get) { + undo_redo->add_do_method(vnode.ptr(),"set_default_input_value",0,d["value"]); + } + undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,base_id); undo_redo->add_do_method(this,"_update_graph"); @@ -1710,25 +2019,24 @@ void VisualScriptEditor::drop_data_fw(const Point2& p_point,const Variant& p_dat - if (use_set) - undo_redo->create_action(TTR("Add Setter Property")); - else + if (use_get) undo_redo->create_action(TTR("Add Getter Property")); + else + undo_redo->create_action(TTR("Add Setter Property")); int base_id = script->get_available_id(); Ref<VisualScriptNode> vnode; - if (use_set) { + if (!use_get) { Ref<VisualScriptPropertySet> pset; pset.instance(); - pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_NODE_PATH); - pset->set_base_path(sn->get_path_to(sn)); - pset->set_property(d["property"]); - if (use_value) { - pset->set_use_builtin_value(true); - pset->set_builtin_value(d["value"]); + if (sn==node) { + pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_SELF); + } else { + pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_NODE_PATH); + pset->set_base_path(sn->get_path_to(node)); } vnode=pset; @@ -1736,13 +2044,20 @@ void VisualScriptEditor::drop_data_fw(const Point2& p_point,const Variant& p_dat Ref<VisualScriptPropertyGet> pget; pget.instance(); - pget->set_call_mode(VisualScriptPropertyGet::CALL_MODE_NODE_PATH); - pget->set_base_path(sn->get_path_to(sn)); - pget->set_property(d["property"]); + if (sn==node) { + pget->set_call_mode(VisualScriptPropertyGet::CALL_MODE_SELF); + } else { + pget->set_call_mode(VisualScriptPropertyGet::CALL_MODE_NODE_PATH); + pget->set_base_path(sn->get_path_to(node)); + } vnode=pget; } undo_redo->add_do_method(script.ptr(),"add_node",edited_func,base_id,vnode,ofs); + undo_redo->add_do_method(vnode.ptr(),"set_property",d["property"]); + if (!use_get) { + undo_redo->add_do_method(vnode.ptr(),"set_default_input_value",0,d["value"]); + } undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,base_id); undo_redo->add_do_method(this,"_update_graph"); @@ -1760,6 +2075,50 @@ void VisualScriptEditor::drop_data_fw(const Point2& p_point,const Variant& p_dat } +void VisualScriptEditor::_selected_method(const String& p_method) { + + Ref<VisualScriptFunctionCall> vsfc = script->get_node(edited_func,selecting_method_id); + if (!vsfc.is_valid()) + return; + vsfc->set_function(p_method); + +} + +void VisualScriptEditor::_draw_color_over_button(Object* obj,Color p_color) { + + Button *button = obj->cast_to<Button>(); + if (!button) + return; + + Ref<StyleBox> normal = get_stylebox("normal","Button" ); + button->draw_rect(Rect2(normal->get_offset(),button->get_size()-normal->get_minimum_size()),p_color); + +} + +void VisualScriptEditor::_button_resource_previewed(const String& p_path,const Ref<Texture>& p_preview,Variant p_ud) { + + + Array ud=p_ud; + ERR_FAIL_COND(ud.size()!=2); + + ObjectID id = ud[0]; + Object *obj = ObjectDB::get_instance(id); + + if (!obj) + return; + + Button *b = obj->cast_to<Button>(); + ERR_FAIL_COND(!b); + + if (p_preview.is_null()) { + b->set_text(ud[1]); + } else { + + b->set_icon(p_preview); + } + +} + ///////////////////////// @@ -1824,7 +2183,8 @@ Ref<Texture> VisualScriptEditor::get_icon(){ bool VisualScriptEditor::is_unsaved(){ #ifdef TOOLS_ENABLED - return script->is_edited(); + + return script->is_edited() || script->are_subnodes_edited(); #else return false; #endif @@ -2254,11 +2614,320 @@ void VisualScriptEditor::_graph_disconnected(const String& p_from,int p_from_slo } + void VisualScriptEditor::_graph_connect_to_empty(const String& p_from,int p_from_slot,const Vector2& p_release_pos) { + Node* node = graph->get_node(p_from); + if (!node) + return; + + GraphNode *gn = node->cast_to<GraphNode>(); + if (!gn) + return; + + Ref<VisualScriptNode> vsn = script->get_node(edited_func,p_from.to_int()); + if (!vsn.is_valid()) + return; + + if (p_from_slot<vsn->get_output_sequence_port_count()) { + + port_action_popup->clear(); + port_action_popup->add_item(TTR("Condition"),CREATE_COND); + port_action_popup->add_item(TTR("Sequence"),CREATE_SEQUENCE); + port_action_popup->add_item(TTR("Switch"),CREATE_SWITCH); + port_action_popup->add_item(TTR("Iterator"),CREATE_ITERATOR); + port_action_popup->add_item(TTR("While"),CREATE_WHILE); + port_action_popup->add_item(TTR("Return"),CREATE_RETURN); + + port_action_node=p_from.to_int(); + port_action_output=p_from_slot; + + } else { + port_action_popup->clear(); + port_action_popup->add_item(TTR("Call"),CREATE_CALL); + port_action_popup->add_item(TTR("Get"),CREATE_GET); + port_action_popup->add_item(TTR("Set"),CREATE_SET); + + + port_action_output=p_from_slot-vsn->get_output_sequence_port_count(); + port_action_node=p_from.to_int(); + + } + + port_action_pos=p_release_pos; + port_action_popup->set_size(Size2(1,1)); + port_action_popup->set_pos(graph->get_global_pos()+p_release_pos); + port_action_popup->popup(); } +VisualScriptNode::TypeGuess VisualScriptEditor::_guess_output_type(int p_node,int p_output,Set<int> &visited_nodes) { + + + VisualScriptNode::TypeGuess tg; + tg.type=Variant::NIL; + + if (visited_nodes.has(p_node)) + return tg; //no loop + + visited_nodes.insert(p_node); + + Ref<VisualScriptNode> node = script->get_node(edited_func,p_node); + + if (!node.is_valid()) { + + return tg; + } + + Vector<VisualScriptNode::TypeGuess> in_guesses; + + for(int i=0;i<node->get_input_value_port_count();i++) { + PropertyInfo pi = node->get_input_value_port_info(i); + VisualScriptNode::TypeGuess g; + g.type=pi.type; + + if (g.type==Variant::NIL || g.type==Variant::OBJECT) { + //any or object input, must further guess what this is + int from_node; + int from_port; + + if (script->get_input_value_port_connection_source(edited_func,p_node,i,&from_node,&from_port)) { + + g = _guess_output_type(from_node,from_port,visited_nodes); + } else { + Variant defval = node->get_default_input_value(i); + if (defval.get_type()==Variant::OBJECT) { + + Object *obj = defval; + + if (obj) { + + g.type=Variant::OBJECT; + g.obj_type=obj->get_type(); + g.script=obj->get_script(); + } + } + } + + } + + in_guesses.push_back(g); + } + + return node->guess_output_type(in_guesses.ptr(),p_output); +} + +void VisualScriptEditor::_port_action_menu(int p_option) { + + Vector2 ofs = graph->get_scroll_ofs() + port_action_pos; + if (graph->is_using_snap()) { + int snap = graph->get_snap(); + ofs = ofs.snapped(Vector2(snap,snap)); + } + ofs/=EDSCALE; + + bool seq_connect=false; + + Ref<VisualScriptNode> vnode; + Set<int> vn; + + switch(p_option) { + + case CREATE_CALL: { + + Ref<VisualScriptFunctionCall> n; + n.instance(); + vnode=n; + + VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node,port_action_output,vn); + + if (tg.type==Variant::OBJECT) { + n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE); + + if (tg.obj_type!=StringName()) { + n->set_base_type(tg.obj_type); + } else { + n->set_base_type("Object"); + } + + if (tg.script.is_valid()) { + n->set_base_script(tg.script->get_path()); + new_connect_node_select->select_method_from_script(tg.script); + } else { + new_connect_node_select->select_method_from_base_type(n->get_base_type()); + } + + + } else { + n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE); + n->set_basic_type(tg.type); + new_connect_node_select->select_method_from_basic_type(tg.type); + } + + + + } break; + case CREATE_SET: { + + Ref<VisualScriptPropertySet> n; + n.instance(); + vnode=n; + + + VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node,port_action_output,vn); + + if (tg.type==Variant::OBJECT) { + n->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE); + + if (tg.obj_type!=StringName()) { + n->set_base_type(tg.obj_type); + } else { + n->set_base_type("Object"); + } + + if (tg.script.is_valid()) { + n->set_base_script(tg.script->get_path()); + new_connect_node_select->select_property_from_script(tg.script); + } else { + new_connect_node_select->select_property_from_base_type(n->get_base_type()); + } + + + } else { + n->set_call_mode(VisualScriptPropertySet::CALL_MODE_BASIC_TYPE); + n->set_basic_type(tg.type); + new_connect_node_select->select_property_from_basic_type(tg.type,tg.ev_type); + } + } break; + case CREATE_GET: { + + Ref<VisualScriptPropertyGet> n; + n.instance(); + vnode=n; + + VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node,port_action_output,vn); + + if (tg.type==Variant::OBJECT) { + n->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE); + + if (tg.obj_type!=StringName()) { + n->set_base_type(tg.obj_type); + } else { + n->set_base_type("Object"); + } + + if (tg.script.is_valid()) { + n->set_base_script(tg.script->get_path()); + new_connect_node_select->select_property_from_script(tg.script); + } else { + new_connect_node_select->select_property_from_base_type(n->get_base_type()); + } + + + } else { + n->set_call_mode(VisualScriptPropertyGet::CALL_MODE_BASIC_TYPE); + n->set_basic_type(tg.type); + new_connect_node_select->select_property_from_basic_type(tg.type,tg.ev_type); + } + + } break; + case CREATE_COND: { + + Ref<VisualScriptCondition> n; + n.instance(); + vnode=n; + seq_connect=true; + + } break; + case CREATE_SEQUENCE: { + + Ref<VisualScriptSequence> n; + n.instance(); + vnode=n; + seq_connect=true; + + } break; + case CREATE_SWITCH: { + + Ref<VisualScriptSwitch> n; + n.instance(); + vnode=n; + seq_connect=true; + + } break; + case CREATE_ITERATOR: { + + Ref<VisualScriptIterator> n; + n.instance(); + vnode=n; + seq_connect=true; + + } break; + case CREATE_WHILE: { + + Ref<VisualScriptWhile> n; + n.instance(); + vnode=n; + seq_connect=true; + + } break; + case CREATE_RETURN: { + + Ref<VisualScriptReturn> n; + n.instance(); + vnode=n; + seq_connect=true; + + } break; + + } + + int new_id = script->get_available_id(); + undo_redo->create_action(TTR("Add Node")); + undo_redo->add_do_method(script.ptr(),"add_node",edited_func,new_id,vnode,ofs); + if (seq_connect) { + undo_redo->add_do_method(script.ptr(),"sequence_connect",edited_func,port_action_node,port_action_output,new_id); + } + undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id); + undo_redo->add_do_method(this,"_update_graph",new_id); + undo_redo->add_undo_method(this,"_update_graph",new_id); + undo_redo->commit_action(); + + port_action_new_node=new_id; + +} + +void VisualScriptEditor::_selected_connect_node_method_or_setget(const String& p_text) { + + Ref<VisualScriptNode> vsn = script->get_node(edited_func,port_action_new_node); + + if (vsn->cast_to<VisualScriptFunctionCall>()) { + + Ref<VisualScriptFunctionCall> vsfc = vsn; + vsfc->set_function(p_text); + script->data_connect(edited_func,port_action_node,port_action_output,port_action_new_node,0); + } + + if (vsn->cast_to<VisualScriptPropertySet>()) { + + Ref<VisualScriptPropertySet> vsp = vsn; + vsp->set_property(p_text); + script->data_connect(edited_func,port_action_node,port_action_output,port_action_new_node,0); + } + + if (vsn->cast_to<VisualScriptPropertyGet>()) { + + Ref<VisualScriptPropertyGet> vsp = vsn; + vsp->set_property(p_text); + script->data_connect(edited_func,port_action_node,port_action_output,port_action_new_node,0); + } + + _update_graph(port_action_new_node); + _update_graph_connections(); + +} + + void VisualScriptEditor::_default_value_changed() { @@ -2294,8 +2963,12 @@ void VisualScriptEditor::_default_value_edited(Node * p_button,int p_id,int p_in default_value_edit->set_pos(p_button->cast_to<Control>()->get_global_pos()+Vector2(0,p_button->cast_to<Control>()->get_size().y)); default_value_edit->set_size(Size2(1,1)); - if (default_value_edit->edit(NULL,pinfo.name,pinfo.type,existing,pinfo.hint,pinfo.hint_string)) - default_value_edit->popup(); + if (default_value_edit->edit(NULL,pinfo.name,pinfo.type,existing,pinfo.hint,pinfo.hint_string)) { + if (pinfo.hint==PROPERTY_HINT_MULTILINE_TEXT) + default_value_edit->popup_centered_ratio(); + else + default_value_edit->popup(); + } editing_id = p_id; editing_input=p_input_port; @@ -2340,6 +3013,39 @@ void VisualScriptEditor::_graph_ofs_changed(const Vector2& p_ofs) { updating_graph=false; } +void VisualScriptEditor::_comment_node_resized(const Vector2& p_new_size,int p_node) { + + if (updating_graph) + return; + + Ref<VisualScriptComment> vsc = script->get_node(edited_func,p_node); + if (vsc.is_null()) + return; + + Node *node = graph->get_node(itos(p_node)); + if (!node) + return; + GraphNode *gn = node->cast_to<GraphNode>(); + if (!gn) + return; + + updating_graph=true; + + graph->set_block_minimum_size_adjust(true); //faster resize + + undo_redo->create_action("Resize Comment",UndoRedo::MERGE_ENDS); + undo_redo->add_do_method(vsc.ptr(),"set_size",p_new_size/EDSCALE); + undo_redo->add_undo_method(vsc.ptr(),"set_size",vsc->get_size()); + undo_redo->commit_action(); + + gn->set_custom_minimum_size(p_new_size); //for this time since graph update is blocked + gn->set_size(Size2(1,1)); + graph->set_block_minimum_size_adjust(false); + updating_graph=false; + + +} + void VisualScriptEditor::_menu_option(int p_what) { switch(p_what) { @@ -2375,8 +3081,151 @@ void VisualScriptEditor::_menu_option(int p_what) { //popup disappearing grabs focus to owner, so use call deferred node_filter->call_deferred("grab_focus"); node_filter->call_deferred("select_all"); + } break; + case EDIT_COPY_NODES: + case EDIT_CUT_NODES: { + + if (!script->has_function(edited_func)) + break; + + clipboard->nodes.clear(); + clipboard->data_connections.clear(); + clipboard->sequence_connections.clear(); + + for(int i=0;i<graph->get_child_count();i++) { + GraphNode *gn = graph->get_child(i)->cast_to<GraphNode>(); + if (gn) { + if (gn->is_selected()) { + + int id = String(gn->get_name()).to_int(); + Ref<VisualScriptNode> node = script->get_node(edited_func,id); + if (node->cast_to<VisualScriptFunction>()) { + EditorNode::get_singleton()->show_warning("Can't copy the function node."); + return; + } + if (node.is_valid()) { + clipboard->nodes[id]=node->duplicate(); + clipboard->nodes_positions[id]=script->get_node_pos(edited_func,id); + } + + } + } + } + + if (clipboard->nodes.empty()) + break; + + List<VisualScript::SequenceConnection> sequence_connections; + + script->get_sequence_connection_list(edited_func,&sequence_connections); + + for (List<VisualScript::SequenceConnection>::Element *E=sequence_connections.front();E;E=E->next()) { + + if (clipboard->nodes.has(E->get().from_node) && clipboard->nodes.has(E->get().to_node)) { + + clipboard->sequence_connections.insert(E->get()); + } + } + + List<VisualScript::DataConnection> data_connections; + + script->get_data_connection_list(edited_func,&data_connections); + + for (List<VisualScript::DataConnection>::Element *E=data_connections.front();E;E=E->next()) { + + if (clipboard->nodes.has(E->get().from_node) && clipboard->nodes.has(E->get().to_node)) { + + clipboard->data_connections.insert(E->get()); + } + } + + if (p_what==EDIT_CUT_NODES) { + _on_nodes_delete(); // oh yeah, also delete on cut + } + + + } break; + case EDIT_PASTE_NODES: { + if (!script->has_function(edited_func)) + break; + + if (clipboard->nodes.empty()) { + EditorNode::get_singleton()->show_warning("Clipboard is empty!"); + break; + } + + Map<int,int> remap; + + undo_redo->create_action("Paste VisualScript Nodes"); + int idc=script->get_available_id()+1; + + Set<int> to_select; + + Set<Vector2> existing_positions; + + { + List<int> nodes; + script->get_node_list(edited_func,&nodes); + for (List<int>::Element *E=nodes.front();E;E=E->next()) { + Vector2 pos = script->get_node_pos(edited_func,E->get()).snapped(Vector2(2,2)); + existing_positions.insert(pos); + } + } + + for (Map<int,Ref<VisualScriptNode> >::Element *E=clipboard->nodes.front();E;E=E->next()) { + + + Ref<VisualScriptNode> node = E->get()->duplicate(); + + int new_id = idc++; + to_select.insert(new_id); + + remap[E->key()]=new_id; + + Vector2 paste_pos = clipboard->nodes_positions[E->key()]; + + while(existing_positions.has(paste_pos.snapped(Vector2(2,2)))) { + paste_pos+=Vector2(20,20)*EDSCALE; + } + + + undo_redo->add_do_method(script.ptr(),"add_node",edited_func,new_id,node,paste_pos); + undo_redo->add_undo_method(script.ptr(),"remove_node",edited_func,new_id); + + } + + for (Set<VisualScript::SequenceConnection>::Element *E=clipboard->sequence_connections.front();E;E=E->next()) { + + + undo_redo->add_do_method(script.ptr(),"sequence_connect",edited_func,remap[E->get().from_node],E->get().from_output,remap[E->get().to_node]); + undo_redo->add_undo_method(script.ptr(),"sequence_disconnect",edited_func,remap[E->get().from_node],E->get().from_output,remap[E->get().to_node]); + + } + + for (Set<VisualScript::DataConnection>::Element *E=clipboard->data_connections.front();E;E=E->next()) { + + + undo_redo->add_do_method(script.ptr(),"data_connect",edited_func,remap[E->get().from_node],E->get().from_port,remap[E->get().to_node],E->get().to_port); + undo_redo->add_undo_method(script.ptr(),"data_disconnect",edited_func,remap[E->get().from_node],E->get().from_port,remap[E->get().to_node],E->get().to_port); + + } + + undo_redo->add_do_method(this,"_update_graph"); + undo_redo->add_undo_method(this,"_update_graph"); + + undo_redo->commit_action(); + + for(int i=0;i<graph->get_child_count();i++) { + GraphNode *gn = graph->get_child(i)->cast_to<GraphNode>(); + if (gn) { + int id = gn->get_name().operator String().to_int(); + gn->set_selected(to_select.has(id)); + + } + } } break; + } } @@ -2403,6 +3252,12 @@ void VisualScriptEditor::_bind_methods() { ObjectTypeDB::bind_method("_menu_option",&VisualScriptEditor::_menu_option); ObjectTypeDB::bind_method("_graph_ofs_changed",&VisualScriptEditor::_graph_ofs_changed); ObjectTypeDB::bind_method("_center_on_node",&VisualScriptEditor::_center_on_node); + ObjectTypeDB::bind_method("_comment_node_resized",&VisualScriptEditor::_comment_node_resized); + ObjectTypeDB::bind_method("_button_resource_previewed",&VisualScriptEditor::_button_resource_previewed); + ObjectTypeDB::bind_method("_port_action_menu",&VisualScriptEditor::_port_action_menu); + ObjectTypeDB::bind_method("_selected_connect_node_method_or_setget",&VisualScriptEditor::_selected_connect_node_method_or_setget); + ObjectTypeDB::bind_method("_expression_text_changed",&VisualScriptEditor::_expression_text_changed); + @@ -2423,6 +3278,11 @@ void VisualScriptEditor::_bind_methods() { ObjectTypeDB::bind_method("_update_graph_connections",&VisualScriptEditor::_update_graph_connections); ObjectTypeDB::bind_method("_node_filter_changed",&VisualScriptEditor::_node_filter_changed); + ObjectTypeDB::bind_method("_selected_method",&VisualScriptEditor::_selected_method); + ObjectTypeDB::bind_method("_draw_color_over_button",&VisualScriptEditor::_draw_color_over_button); + + + } @@ -2430,6 +3290,9 @@ void VisualScriptEditor::_bind_methods() { VisualScriptEditor::VisualScriptEditor() { + if (!clipboard) { + clipboard = memnew( Clipboard ); + } updating_graph=false; edit_menu = memnew( MenuButton ); @@ -2437,6 +3300,11 @@ VisualScriptEditor::VisualScriptEditor() { edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/delete_selected"), EDIT_DELETE_NODES); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/toggle_breakpoint"), EDIT_TOGGLE_BREAKPOINT); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/find_node_type"), EDIT_FIND_NODE_TYPE); + edit_menu->get_popup()->add_separator(); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/copy_nodes"), EDIT_COPY_NODES); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/cut_nodes"), EDIT_CUT_NODES); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/paste_nodes"), EDIT_PASTE_NODES); + edit_menu->get_popup()->connect("item_pressed",this,"_menu_option"); main_hsplit = memnew( HSplitContainer ); @@ -2449,9 +3317,9 @@ VisualScriptEditor::VisualScriptEditor() { VBoxContainer *left_vb = memnew( VBoxContainer ); left_vsplit->add_child(left_vb); left_vb->set_v_size_flags(SIZE_EXPAND_FILL); - left_vb->set_custom_minimum_size(Size2(180,1)*EDSCALE); + left_vb->set_custom_minimum_size(Size2(230,1)*EDSCALE); - base_type_select = memnew( Button ); + base_type_select = memnew( Button ); left_vb->add_margin_child(TTR("Base Type:"),base_type_select); base_type_select->connect("pressed",this,"_change_base_type"); @@ -2588,7 +3456,20 @@ VisualScriptEditor::VisualScriptEditor() { add_child(default_value_edit); default_value_edit->connect("variant_changed",this,"_default_value_changed"); + method_select = memnew( PropertySelector ); + add_child(method_select); + method_select->connect("selected",this,"_selected_method"); error_line=-1; + + new_connect_node_select = memnew( PropertySelector ); + add_child(new_connect_node_select); + new_connect_node_select->connect("selected",this,"_selected_connect_node_method_or_setget"); + + port_action_popup = memnew( PopupMenu ); + add_child(port_action_popup); + port_action_popup->connect("item_pressed",this,"_port_action_menu"); + + } VisualScriptEditor::~VisualScriptEditor() { @@ -2607,6 +3488,14 @@ static ScriptEditorBase * create_editor(const Ref<Script>& p_script) { return NULL; } + +VisualScriptEditor::Clipboard *VisualScriptEditor::clipboard=NULL; + +void VisualScriptEditor::free_clipboard() { + if (clipboard) + memdelete(clipboard); +} + static void register_editor_callback() { ScriptEditor::register_create_script_editor_function(create_editor); @@ -2615,11 +3504,15 @@ static void register_editor_callback() { 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)); + EditorSettings::get_singleton()->set("visual_script_editor/color_constants",Color(1.0,0.8,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); + ED_SHORTCUT("visual_script_editor/find_node_type", TTR("Find Node Type"), KEY_MASK_CMD+KEY_F); + ED_SHORTCUT("visual_script_editor/copy_nodes", TTR("Copy Nodes"), KEY_MASK_CMD+KEY_C); + ED_SHORTCUT("visual_script_editor/cut_nodes", TTR("Cut Nodes"), KEY_MASK_CMD+KEY_X); + ED_SHORTCUT("visual_script_editor/paste_nodes", TTR("Paste Nodes"), KEY_MASK_CMD+KEY_V); } diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h index 1ce7e5a6c7..483ae1644c 100644 --- a/modules/visual_script/visual_script_editor.h +++ b/modules/visual_script/visual_script_editor.h @@ -6,13 +6,14 @@ #include "tools/editor/property_editor.h" #include "scene/gui/graph_edit.h" #include "tools/editor/create_dialog.h" - +#include "tools/editor/property_selector.h" class VisualScriptEditorSignalEdit; class VisualScriptEditorVariableEdit; #ifdef TOOLS_ENABLED + class VisualScriptEditor : public ScriptEditorBase { OBJ_TYPE(VisualScriptEditor,ScriptEditorBase) @@ -27,6 +28,22 @@ class VisualScriptEditor : public ScriptEditorBase { EDIT_DELETE_NODES, EDIT_TOGGLE_BREAKPOINT, EDIT_FIND_NODE_TYPE, + EDIT_COPY_NODES, + EDIT_CUT_NODES, + EDIT_PASTE_NODES, + }; + + enum PortAction { + + CREATE_CALL, + CREATE_SET, + CREATE_GET, + CREATE_COND, + CREATE_SEQUENCE, + CREATE_SWITCH, + CREATE_ITERATOR, + CREATE_WHILE, + CREATE_RETURN, }; MenuButton *edit_menu; @@ -48,6 +65,8 @@ class VisualScriptEditor : public ScriptEditorBase { AcceptDialog *edit_signal_dialog; PropertyEditor *edit_signal_edit; + PropertySelector *method_select; + PropertySelector *new_connect_node_select; VisualScriptEditorVariableEdit *variable_editor; @@ -98,6 +117,27 @@ class VisualScriptEditor : public ScriptEditorBase { String _validate_name(const String& p_name) const; + struct Clipboard { + + Map<int,Ref<VisualScriptNode> > nodes; + Map<int,Vector2 > nodes_positions; + + Set<VisualScript::SequenceConnection> sequence_connections; + Set<VisualScript::DataConnection> data_connections; + }; + + static Clipboard *clipboard; + + PopupMenu *port_action_popup; + + PortAction port_action; + int port_action_node; + int port_action_output; + Vector2 port_action_pos; + int port_action_new_node; + void _port_action_menu(int p_option); + void _selected_connect_node_method_or_setget(const String& p_text); + int error_line; @@ -128,6 +168,8 @@ class VisualScriptEditor : public ScriptEditorBase { void _member_button(Object *p_item, int p_column, int p_button); + void _expression_text_changed(const String& p_text,int p_id); + String revert_on_drag; @@ -149,6 +191,15 @@ class VisualScriptEditor : public ScriptEditorBase { void _menu_option(int p_what); void _graph_ofs_changed(const Vector2& p_ofs); + void _comment_node_resized(const Vector2& p_new_size,int p_node); + + int selecting_method_id; + void _selected_method(const String& p_method); + + void _draw_color_over_button(Object* obj,Color p_color); + void _button_resource_previewed(const String& p_path,const Ref<Texture>& p_preview,Variant p_ud); + + VisualScriptNode::TypeGuess _guess_output_type(int p_port_action_node,int p_port_action_output,Set<int> &visited_nodes); protected: @@ -179,9 +230,12 @@ public: virtual void set_debugger_active(bool p_active); virtual void set_tooltip_request_func(String p_method,Object* p_obj); virtual Control *get_edit_menu(); + virtual bool can_lose_focus_on_node_selection() { return false; } static void register_editor(); + static void free_clipboard(); + VisualScriptEditor(); ~VisualScriptEditor(); }; diff --git a/modules/visual_script/visual_script_expression.cpp b/modules/visual_script/visual_script_expression.cpp new file mode 100644 index 0000000000..cc3b5f2174 --- /dev/null +++ b/modules/visual_script/visual_script_expression.cpp @@ -0,0 +1,1523 @@ +#include "visual_script_expression.h" + + +bool VisualScriptExpression::_set(const StringName& p_name, const Variant& p_value) { + + if (String(p_name)=="expression") { + expression=p_value; + expression_dirty=true; + ports_changed_notify(); + return true; + } + + if (String(p_name)=="out_type") { + output_type=Variant::Type(int(p_value)); + expression_dirty=true; + ports_changed_notify(); + return true; + } + if (String(p_name)=="sequenced") { + sequenced=p_value; + ports_changed_notify(); + return true; + } + + if (String(p_name)=="input_count") { + + int from=inputs.size(); + inputs.resize(int(p_value)); + for(int i=from;i<inputs.size();i++) { + inputs[i].name=String::chr('a'+i); + if (from==0) { + inputs[i].type=output_type; + } else { + inputs[i].type=inputs[from-1].type; + } + } + expression_dirty=true; + ports_changed_notify(); + _change_notify(); + return true; + } + + if (String(p_name).begins_with("input/")) { + + int idx=String(p_name).get_slice("/",1).to_int(); + ERR_FAIL_INDEX_V(idx,inputs.size(),false); + + String what=String(p_name).get_slice("/",2); + + if (what=="type") { + + inputs[idx].type=Variant::Type(int(p_value)); + } else if (what=="name") { + + inputs[idx].name=p_value; + } else { + return false; + } + + expression_dirty=true; + ports_changed_notify(); + return true; + } + + + return false; + +} + +bool VisualScriptExpression::_get(const StringName& p_name,Variant &r_ret) const { + + if (String(p_name)=="expression") { + r_ret=expression; + return true; + } + + if (String(p_name)=="out_type") { + r_ret=output_type; + return true; + } + + if (String(p_name)=="sequenced") { + r_ret=sequenced; + return true; + } + + if (String(p_name)=="input_count") { + r_ret=inputs.size(); + return true; + } + + if (String(p_name).begins_with("input/")) { + + int idx=String(p_name).get_slice("/",1).to_int(); + ERR_FAIL_INDEX_V(idx,inputs.size(),false); + + String what=String(p_name).get_slice("/",2); + + if (what=="type") { + + r_ret=inputs[idx].type; + } else if (what=="name") { + + r_ret=inputs[idx].name; + } else { + return false; + } + + return true; + } + + + return false; +} +void VisualScriptExpression::_get_property_list( List<PropertyInfo> *p_list) const { + + + String argt="Any"; + for(int i=1;i<Variant::VARIANT_MAX;i++) { + argt+=","+Variant::get_type_name(Variant::Type(i)); + } + + p_list->push_back(PropertyInfo(Variant::STRING,"expression",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR)); + p_list->push_back(PropertyInfo(Variant::INT,"out_type",PROPERTY_HINT_ENUM,argt)); + p_list->push_back(PropertyInfo(Variant::INT,"input_count",PROPERTY_HINT_RANGE,"0,64,1")); + p_list->push_back(PropertyInfo(Variant::BOOL,"sequenced")); + + for(int i=0;i<inputs.size();i++) { + + p_list->push_back(PropertyInfo(Variant::INT,"input/"+itos(i)+"/type",PROPERTY_HINT_ENUM,argt)); + p_list->push_back(PropertyInfo(Variant::STRING,"input/"+itos(i)+"/name")); + } +} + +int VisualScriptExpression::get_output_sequence_port_count() const { + + return sequenced?1:0; +} +bool VisualScriptExpression::has_input_sequence_port() const{ + + return sequenced; +} + + +String VisualScriptExpression::get_output_sequence_port_text(int p_port) const{ + + return String(); +} + + +int VisualScriptExpression::get_input_value_port_count() const{ + + return inputs.size(); + +} +int VisualScriptExpression::get_output_value_port_count() const{ + + return 1; +} + + +PropertyInfo VisualScriptExpression::get_input_value_port_info(int p_idx) const{ + + return PropertyInfo(inputs[p_idx].type,inputs[p_idx].name); +} +PropertyInfo VisualScriptExpression::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(output_type,"result"); +} + +String VisualScriptExpression::get_caption() const{ + + return "Expression"; +} +String VisualScriptExpression::get_text() const{ + + return expression; +} + + +Error VisualScriptExpression::_get_token(Token& r_token) { + + while (true) { +#define GET_CHAR() (str_ofs>=expression.length()?0:expression[str_ofs++]) + + CharType cchar = GET_CHAR(); + if (cchar==0) { + r_token.type=TK_EOF; + return OK; + } + + + switch(cchar) { + + case 0: { + r_token.type=TK_EOF; + return OK; + } break; + case '{': { + + r_token.type=TK_CURLY_BRACKET_OPEN; + return OK; + }; + case '}': { + + r_token.type=TK_CURLY_BRACKET_CLOSE; + return OK; + }; + case '[': { + + r_token.type=TK_BRACKET_OPEN; + return OK; + }; + case ']': { + + r_token.type=TK_BRACKET_CLOSE; + return OK; + }; + case '(': { + + r_token.type=TK_PARENTHESIS_OPEN; + return OK; + }; + case ')': { + + r_token.type=TK_PARENTHESIS_CLOSE; + return OK; + }; + case ',': { + + r_token.type=TK_COMMA; + return OK; + }; + case ':': { + + r_token.type=TK_COLON; + return OK; + }; + case '.': { + + r_token.type=TK_PERIOD; + return OK; + }; + case '=': { + + cchar=GET_CHAR(); + if (cchar=='=') { + r_token.type=TK_OP_EQUAL; + } else { + _set_error("Expected '='"); + r_token.type=TK_ERROR; + return ERR_PARSE_ERROR; + } + return OK; + }; + case '!': { + + if (expression[str_ofs]=='=') { + r_token.type=TK_OP_NOT_EQUAL; + str_ofs++; + } else { + r_token.type=TK_OP_NOT; + } + return OK; + }; + case '>': { + + if (expression[str_ofs]=='=') { + r_token.type=TK_OP_GREATER_EQUAL; + str_ofs++; + } else if (expression[str_ofs]=='>') { + r_token.type=TK_OP_SHIFT_RIGHT; + str_ofs++; + } else { + r_token.type=TK_OP_GREATER; + } + return OK; + }; + case '<': { + + if (expression[str_ofs]=='=') { + r_token.type=TK_OP_LESS_EQUAL; + str_ofs++; + } else if (expression[str_ofs]=='<') { + r_token.type=TK_OP_SHIFT_LEFT; + str_ofs++; + } else { + r_token.type=TK_OP_LESS; + } + return OK; + }; + case '+': { + r_token.type=TK_OP_ADD; + return OK; + }; + case '-': { + r_token.type=TK_OP_SUB; + return OK; + }; + case '/': { + r_token.type=TK_OP_DIV; + return OK; + }; + case '*': { + r_token.type=TK_OP_MUL; + return OK; + }; + case '%': { + r_token.type=TK_OP_MOD; + return OK; + }; + case '&': { + + if (expression[str_ofs]=='&') { + r_token.type=TK_OP_AND; + str_ofs++; + } else { + r_token.type=TK_OP_BIT_AND; + } + return OK; + }; + case '|': { + + if (expression[str_ofs]=='|') { + r_token.type=TK_OP_OR; + str_ofs++; + } else { + r_token.type=TK_OP_BIT_OR; + } + return OK; + }; + case '^': { + + r_token.type=TK_OP_BIT_XOR; + + return OK; + }; + case '~': { + + r_token.type=TK_OP_BIT_INVERT; + + return OK; + }; + case '"': { + + + String str; + while(true) { + + CharType ch=GET_CHAR(); + + if (ch==0) { + _set_error("Unterminated String"); + r_token.type=TK_ERROR; + return ERR_PARSE_ERROR; + } else if (ch=='"') { + break; + } else if (ch=='\\') { + //escaped characters... + + CharType next = GET_CHAR(); + if (next==0) { + _set_error("Unterminated String"); + r_token.type=TK_ERROR; + return ERR_PARSE_ERROR; + } + CharType res=0; + + switch(next) { + + case 'b': res=8; break; + case 't': res=9; break; + case 'n': res=10; break; + case 'f': res=12; break; + case 'r': res=13; break; + case 'u': { + //hexnumbarh - oct is deprecated + + + for(int j=0;j<4;j++) { + CharType c = GET_CHAR(); + + if (c==0) { + _set_error("Unterminated String"); + r_token.type=TK_ERROR; + return ERR_PARSE_ERROR; + } + if (!((c>='0' && c<='9') || (c>='a' && c<='f') || (c>='A' && c<='F'))) { + + _set_error("Malformed hex constant in string"); + r_token.type=TK_ERROR; + return ERR_PARSE_ERROR; + } + CharType v; + if (c>='0' && c<='9') { + v=c-'0'; + } else if (c>='a' && c<='f') { + v=c-'a'; + v+=10; + } else if (c>='A' && c<='F') { + v=c-'A'; + v+=10; + } else { + ERR_PRINT("BUG"); + v=0; + } + + res<<=4; + res|=v; + + + } + + + + } break; + //case '\"': res='\"'; break; + //case '\\': res='\\'; break; + //case '/': res='/'; break; + default: { + res = next; + //r_err_str="Invalid escape sequence"; + //return ERR_PARSE_ERROR; + } break; + } + + str+=res; + + } else { + str+=ch; + } + } + + r_token.type=TK_CONSTANT; + r_token.value=str; + return OK; + + } break; + default: { + + if (cchar<=32) { + break; + } + + if (cchar=='-' || (cchar>='0' && cchar<='9')) { + //a number + + + String num; +#define READING_SIGN 0 +#define READING_INT 1 +#define READING_DEC 2 +#define READING_EXP 3 +#define READING_DONE 4 + int reading=READING_INT; + + if (cchar=='-') { + num+='-'; + cchar=GET_CHAR(); + + } + + + + CharType c = cchar; + bool exp_sign=false; + bool exp_beg=false; + bool is_float=false; + + while(true) { + + switch(reading) { + case READING_INT: { + + if (c>='0' && c<='9') { + //pass + } else if (c=='.') { + reading=READING_DEC; + is_float=true; + } else if (c=='e') { + reading=READING_EXP; + } else { + reading=READING_DONE; + } + + } break; + case READING_DEC: { + + if (c>='0' && c<='9') { + + } else if (c=='e') { + reading=READING_EXP; + + } else { + reading=READING_DONE; + } + + } break; + case READING_EXP: { + + if (c>='0' && c<='9') { + exp_beg=true; + + } else if ((c=='-' || c=='+') && !exp_sign && !exp_beg) { + if (c=='-') + is_float=true; + exp_sign=true; + + } else { + reading=READING_DONE; + } + } break; + } + + if (reading==READING_DONE) + break; + num+=String::chr(c); + c = GET_CHAR(); + + + } + + str_ofs--; + + r_token.type=TK_CONSTANT; + + if (is_float) + r_token.value=num.to_double(); + else + r_token.value=num.to_int(); + return OK; + + } else if ((cchar>='A' && cchar<='Z') || (cchar>='a' && cchar<='z') || cchar=='_') { + + String id; + bool first=true; + + while((cchar>='A' && cchar<='Z') || (cchar>='a' && cchar<='z') || cchar=='_' || (!first && cchar>='0' && cchar<='9')) { + + id+=String::chr(cchar); + cchar=GET_CHAR(); + first=false; + } + + str_ofs--; //go back one + + if (id=="in") { + r_token.type=TK_OP_IN; + } else if (id=="null") { + r_token.type=TK_CONSTANT; + r_token.value=Variant(); + } else if (id=="true") { + r_token.type=TK_CONSTANT; + r_token.value=true; + } else if (id=="false") { + r_token.type=TK_CONSTANT; + r_token.value=false; + } else if (id=="PI") { + r_token.type=TK_CONSTANT; + r_token.value=Math_PI; + } else if (id=="not") { + r_token.type=TK_OP_NOT; + } else if (id=="or") { + r_token.type=TK_OP_OR; + } else if (id=="and") { + r_token.type=TK_OP_AND; + } else if (id=="self") { + r_token.type=TK_SELF; + } else { + + for(int i=0;i<Variant::VARIANT_MAX;i++) { + if (id==Variant::get_type_name(Variant::Type(i))) { + r_token.type=TK_BASIC_TYPE; + r_token.value=i; + return OK; + break; + } + } + + VisualScriptBuiltinFunc::BuiltinFunc bifunc = VisualScriptBuiltinFunc::find_function(id); + if (bifunc!=VisualScriptBuiltinFunc::FUNC_MAX) { + r_token.type=TK_BUILTIN_FUNC; + r_token.value=bifunc; + return OK; + } + + r_token.type=TK_IDENTIFIER; + r_token.value=id; + } + + return OK; + } else { + _set_error("Unexpected character."); + r_token.type=TK_ERROR; + return ERR_PARSE_ERROR; + } + } + } + } + + r_token.type=TK_ERROR; + return ERR_PARSE_ERROR; +} + +const char* VisualScriptExpression::token_name[TK_MAX]={ +"CURLY BRACKET OPEN", +"CURLY BRACKET CLOSE", +"BRACKET OPEN", +"BRACKET CLOSE", +"PARENTHESIS OPEN", +"PARENTHESIS CLOSE", +"IDENTIFIER", +"BUILTIN FUNC", +"SELF", +"CONSTANT", +"BASIC TYPE", +"COLON", +"COMMA", +"PERIOD", +"OP IN", +"OP EQUAL", +"OP NOT EQUAL", +"OP LESS", +"OP LESS EQUAL", +"OP GREATER", +"OP GREATER EQUAL", +"OP AND", +"OP OR", +"OP NOT", +"OP ADD", +"OP SUB", +"OP MUL", +"OP DIV", +"OP MOD", +"OP SHIFT LEFT", +"OP SHIFT RIGHT", +"OP BIT AND", +"OP BIT OR", +"OP BIT XOR", +"OP BIT INVERT", +"EOF", +"ERROR" +}; + +VisualScriptExpression::ENode* VisualScriptExpression::_parse_expression() { + + + Vector<Expression> expression; + + while(true) { + //keep appending stuff to expression + ENode*expr=NULL; + + Token tk; + _get_token(tk); + if (error_set) + return NULL; + + + + switch(tk.type) { + case TK_CURLY_BRACKET_OPEN: { + //a dictionary + DictionaryNode *dn = alloc_node<DictionaryNode>(); + + + while(true) { + + int cofs=str_ofs; + _get_token(tk); + if (tk.type==TK_CURLY_BRACKET_CLOSE) { + break; + } + str_ofs=cofs; //revert + //parse an expression + ENode* expr=_parse_expression(); + if (!expr) + return NULL; + dn->dict.push_back(expr); + + _get_token(tk); + if (tk.type!=TK_COLON) { + _set_error("Expected ':'"); + return NULL; + } + + expr=_parse_expression(); + if (!expr) + return NULL; + + dn->dict.push_back(expr); + + cofs=str_ofs; + _get_token(tk); + if (tk.type==TK_COMMA) { + //all good + } else if (tk.type==TK_CURLY_BRACKET_CLOSE) { + str_ofs=cofs; + } else { + _set_error("Expected ',' or '}'"); + } + } + + expr=dn; + } break; + case TK_BRACKET_OPEN: { + //an array + + ArrayNode *an = alloc_node<ArrayNode>(); + + + while(true) { + + int cofs=str_ofs; + _get_token(tk); + if (tk.type==TK_BRACKET_CLOSE) { + break; + } + str_ofs=cofs; //revert + //parse an expression + ENode* expr=_parse_expression(); + if (!expr) + return NULL; + an->array.push_back(expr); + + cofs=str_ofs; + _get_token(tk); + if (tk.type==TK_COMMA) { + //all good + } else if (tk.type==TK_BRACKET_CLOSE) { + str_ofs=cofs; + } else { + _set_error("Expected ',' or ']'"); + } + } + + expr=an; + } break; + case TK_PARENTHESIS_OPEN: { + //a suexpression + ENode* e=_parse_expression(); + if (error_set) + return NULL; + _get_token(tk); + if (tk.type!=TK_PARENTHESIS_CLOSE) { + _set_error("Expected ')'"); + return NULL; + } + + expr=e; + + } break; + case TK_IDENTIFIER: { + + String what = tk.value; + int index=-1; + for(int i=0;i<inputs.size();i++) { + if (what==inputs[i].name) { + index=i; + break; + } + } + + if (index!=-1) { + InputNode *input = alloc_node<InputNode>(); + input->index=index; + expr=input; + } else { + _set_error("Invalid input identifier '"+what+"'. For script variables, use self (locals are for inputs)."+what); + return NULL; + } + } break; + case TK_SELF: { + + SelfNode *self = alloc_node<SelfNode>(); + expr=self; + } break; + case TK_CONSTANT: { + ConstantNode *constant = alloc_node<ConstantNode>(); + constant->value=tk.value; + expr=constant; + } break; + case TK_BASIC_TYPE: { + //constructor.. + + Variant::Type bt = Variant::Type(int(tk.value)); + _get_token(tk); + if (tk.type!=TK_PARENTHESIS_OPEN) { + _set_error("Expected '('"); + return NULL; + } + + ConstructorNode *constructor = alloc_node<ConstructorNode>(); + constructor->data_type=bt; + + while(true) { + + int cofs=str_ofs; + _get_token(tk); + if (tk.type==TK_PARENTHESIS_CLOSE) { + break; + } + str_ofs=cofs; //revert + //parse an expression + ENode* expr=_parse_expression(); + if (!expr) + return NULL; + + constructor->arguments.push_back(expr); + + cofs=str_ofs; + _get_token(tk); + if (tk.type==TK_COMMA) { + //all good + } else if (tk.type==TK_PARENTHESIS_CLOSE) { + str_ofs=cofs; + } else { + _set_error("Expected ',' or ')'"); + } + } + + expr=constructor; + + } break; + case TK_BUILTIN_FUNC: { + //builtin function + + Variant::Type bt = Variant::Type(int(tk.value)); + _get_token(tk); + if (tk.type!=TK_PARENTHESIS_OPEN) { + _set_error("Expected '('"); + return NULL; + } + + BuiltinFuncNode *bifunc = alloc_node<BuiltinFuncNode>(); + bifunc->func=VisualScriptBuiltinFunc::BuiltinFunc(int(tk.value)); + + while(true) { + + int cofs=str_ofs; + _get_token(tk); + if (tk.type==TK_PARENTHESIS_CLOSE) { + break; + } + str_ofs=cofs; //revert + //parse an expression + ENode* expr=_parse_expression(); + if (!expr) + return NULL; + + bifunc->arguments.push_back(expr); + + cofs=str_ofs; + _get_token(tk); + if (tk.type==TK_COMMA) { + //all good + } else if (tk.type==TK_PARENTHESIS_CLOSE) { + str_ofs=cofs; + } else { + _set_error("Expected ',' or ')'"); + } + } + + int expected_args = VisualScriptBuiltinFunc::get_func_argument_count(bifunc->func); + if (bifunc->arguments.size() != expected_args) { + _set_error("Builtin func '"+VisualScriptBuiltinFunc::get_func_name(bifunc->func)+"' expects "+itos(expected_args)+" arguments."); + } + + expr=bifunc; + + } break; + case TK_OP_SUB: { + + Expression e; + e.is_op=true; + e.op=Variant::OP_NEGATE; + expression.push_back(e); + continue; + } break; + case TK_OP_NOT: { + + Expression e; + e.is_op=true; + e.op=Variant::OP_NOT; + expression.push_back(e); + continue; + } break; + + default: { + _set_error("Expected expression."); + return NULL; + } break; + + } + + //before going to operators, must check indexing! + + while(true) { + int cofs2=str_ofs; + _get_token(tk); + if (error_set) + return NULL; + + bool done=false; + + switch(tk.type) { + case TK_BRACKET_OPEN: { + //value indexing + + IndexNode *index = alloc_node<IndexNode>(); + index->base=expr; + + ENode* what=_parse_expression(); + if (!what) + return NULL; + + index->index=what; + + _get_token(tk); + if (tk.type!=TK_BRACKET_CLOSE) { + _set_error("Expected ']' at end of index."); + return NULL; + } + expr=index; + + } break; + case TK_PERIOD: { + //named indexing or function call + _get_token(tk); + if (tk.type!=TK_IDENTIFIER) { + _set_error("Expected identifier after '.'"); + return NULL; + } + + StringName identifier=tk.value; + + int cofs=str_ofs; + _get_token(tk); + if (tk.type==TK_PARENTHESIS_OPEN) { + //function call + CallNode *func_call = alloc_node<CallNode>(); + func_call->method=identifier; + func_call->base=expr; + + while(true) { + + int cofs=str_ofs; + _get_token(tk); + if (tk.type==TK_PARENTHESIS_CLOSE) { + break; + } + str_ofs=cofs; //revert + //parse an expression + ENode* expr=_parse_expression(); + if (!expr) + return NULL; + + func_call->arguments.push_back(expr); + + cofs=str_ofs; + _get_token(tk); + if (tk.type==TK_COMMA) { + //all good + } else if (tk.type==TK_PARENTHESIS_CLOSE) { + str_ofs=cofs; + } else { + _set_error("Expected ',' or ')'"); + } + } + + expr=func_call; + } else { + //named indexing + str_ofs=cofs; + + NamedIndexNode *index = alloc_node<NamedIndexNode>(); + index->base=expr; + index->name=identifier; + expr=index; + + } + + } break; + default: { + str_ofs=cofs2; + done=true; + } break; + } + + if (done) + break; + } + + //push expression + { + Expression e; + e.is_op=false; + e.node=expr; + expression.push_back(e); + } + + //ok finally look for an operator + + + int cofs=str_ofs; + _get_token(tk); + if (error_set) + return NULL; + + + Variant::Operator op = Variant::OP_MAX; + + switch(tk.type) { + case TK_OP_IN: op=Variant::OP_IN; break; + case TK_OP_EQUAL: op=Variant::OP_EQUAL; break; + case TK_OP_NOT_EQUAL: op=Variant::OP_NOT_EQUAL; break; + case TK_OP_LESS: op=Variant::OP_LESS; break; + case TK_OP_LESS_EQUAL: op=Variant::OP_LESS_EQUAL; break; + case TK_OP_GREATER: op=Variant::OP_GREATER; break; + case TK_OP_GREATER_EQUAL: op=Variant::OP_GREATER_EQUAL; break; + case TK_OP_AND: op=Variant::OP_AND; break; + case TK_OP_OR: op=Variant::OP_OR; break; + case TK_OP_NOT: op=Variant::OP_NOT; break; + case TK_OP_ADD: op=Variant::OP_ADD; break; + case TK_OP_SUB: op=Variant::OP_SUBSTRACT; break; + case TK_OP_MUL: op=Variant::OP_MULTIPLY; break; + case TK_OP_DIV: op=Variant::OP_DIVIDE; break; + case TK_OP_MOD: op=Variant::OP_MODULE; break; + case TK_OP_SHIFT_LEFT: op=Variant::OP_SHIFT_LEFT; break; + case TK_OP_SHIFT_RIGHT: op=Variant::OP_SHIFT_RIGHT; break; + case TK_OP_BIT_AND: op=Variant::OP_BIT_AND; break; + case TK_OP_BIT_OR: op=Variant::OP_BIT_OR; break; + case TK_OP_BIT_XOR: op=Variant::OP_BIT_XOR; break; + case TK_OP_BIT_INVERT: op=Variant::OP_BIT_NEGATE; break; + default: {}; + } + + if (op==Variant::OP_MAX) { //stop appending stuff + str_ofs=cofs; + break; + } + + //push operator and go on + { + Expression e; + e.is_op=true; + e.op=op; + expression.push_back(e); + } + } + + + /* Reduce the set set of expressions and place them in an operator tree, respecting precedence */ + + + while(expression.size()>1) { + + int next_op=-1; + int min_priority=0xFFFFF; + bool is_unary=false; + + for(int i=0;i<expression.size();i++) { + + + + if (!expression[i].is_op) { + + continue; + } + + int priority; + + bool unary=false; + + switch(expression[i].op) { + + + case Variant::OP_BIT_NEGATE: priority=0; unary=true; break; + case Variant::OP_NEGATE: priority=1; unary=true; break; + + case Variant::OP_MULTIPLY: priority=2; break; + case Variant::OP_DIVIDE: priority=2; break; + case Variant::OP_MODULE: priority=2; break; + + case Variant::OP_ADD: priority=3; break; + case Variant::OP_SUBSTRACT: priority=3; break; + + case Variant::OP_SHIFT_LEFT: priority=4; break; + case Variant::OP_SHIFT_RIGHT: priority=4; break; + + case Variant::OP_BIT_AND: priority=5; break; + case Variant::OP_BIT_XOR: priority=6; break; + case Variant::OP_BIT_OR: priority=7; break; + + case Variant::OP_LESS: priority=8; break; + case Variant::OP_LESS_EQUAL: priority=8; break; + case Variant::OP_GREATER: priority=8; break; + case Variant::OP_GREATER_EQUAL: priority=8; break; + + case Variant::OP_EQUAL: priority=8; break; + case Variant::OP_NOT_EQUAL: priority=8; break; + + case Variant::OP_IN: priority=10; break; + + case Variant::OP_NOT: priority=11; unary=true; break; + case Variant::OP_AND: priority=12; break; + case Variant::OP_OR: priority=13; break; + + + default: { + _set_error("Parser bug, invalid operator in expression: "+itos(expression[i].op)); + return NULL; + } + + } + + if (priority<min_priority) { + // < is used for left to right (default) + // <= is used for right to left + + next_op=i; + min_priority=priority; + is_unary=unary; + } + + } + + if (next_op==-1) { + + + _set_error("Yet another parser bug...."); + ERR_FAIL_COND_V(next_op==-1,NULL); + } + + + // OK! create operator.. + if (is_unary) { + + int expr_pos=next_op; + while(expression[expr_pos].is_op) { + + expr_pos++; + if (expr_pos==expression.size()) { + //can happen.. + _set_error("Unexpected end of expression.."); + return NULL; + } + } + + //consecutively do unary opeators + for(int i=expr_pos-1;i>=next_op;i--) { + + OperatorNode *op = alloc_node<OperatorNode>(); + op->op=expression[i].op; + op->nodes[0]=expression[i+1].node; + op->nodes[1]=NULL; + expression[i].is_op=false; + expression[i].node=op; + expression.remove(i+1); + } + + + } else { + + if (next_op <1 || next_op>=(expression.size()-1)) { + _set_error("Parser bug.."); + ERR_FAIL_V(NULL); + } + + OperatorNode *op = alloc_node<OperatorNode>(); + op->op=expression[next_op].op; + + if (expression[next_op-1].is_op) { + + _set_error("Parser bug.."); + ERR_FAIL_V(NULL); + } + + if (expression[next_op+1].is_op) { + // this is not invalid and can really appear + // but it becomes invalid anyway because no binary op + // can be followed by an unary op in a valid combination, + // due to how precedence works, unaries will always dissapear first + + _set_error("Unexpected two consecutive operators."); + return NULL; + } + + + op->nodes[0]=expression[next_op-1].node; //expression goes as left + op->nodes[1]=expression[next_op+1].node; //next expression goes as right + + //replace all 3 nodes by this operator and make it an expression + expression[next_op-1].node=op; + expression.remove(next_op); + expression.remove(next_op); + } + } + + return expression[0].node; +} + +bool VisualScriptExpression::_compile_expression() { + + if (!expression_dirty) + return error_set; + + if (nodes) { + memdelete(nodes); + nodes=NULL; + root=NULL; + + } + + error_str=String(); + error_set=false; + str_ofs=0; + + root=_parse_expression(); + + if (error_set) { + root=NULL; + if (nodes) { + memdelete(nodes); + } + nodes=NULL; + return true; + } + + expression_dirty=false; + return false; +} + + +class VisualScriptNodeInstanceExpression : public VisualScriptNodeInstance { +public: + + VisualScriptInstance* instance; + VisualScriptExpression *expression; + + //virtual int get_working_memory_size() const { return 0; } + //execute by parsing the tree directly + virtual bool _execute(const Variant** p_inputs,VisualScriptExpression::ENode *p_node,Variant& r_ret,String& r_error_str,Variant::CallError &ce) { + + switch(p_node->type) { + case VisualScriptExpression::ENode::TYPE_INPUT: { + + const VisualScriptExpression::InputNode *in = static_cast<const VisualScriptExpression::InputNode*>(p_node); + r_ret=*p_inputs[in->index]; + } break; + case VisualScriptExpression::ENode::TYPE_CONSTANT: { + + const VisualScriptExpression::ConstantNode *c = static_cast<const VisualScriptExpression::ConstantNode*>(p_node); + r_ret=c->value; + + } break; + case VisualScriptExpression::ENode::TYPE_SELF: { + + r_ret=instance->get_owner_ptr(); + } break; + case VisualScriptExpression::ENode::TYPE_OPERATOR: { + + + const VisualScriptExpression::OperatorNode *op = static_cast<const VisualScriptExpression::OperatorNode*>(p_node); + + Variant a; + bool ret = _execute(p_inputs,op->nodes[0],a,r_error_str,ce); + if (ret) + return true; + + Variant b; + + if (op->nodes[1]) { + ret = _execute(p_inputs,op->nodes[1],b,r_error_str,ce); + if (ret) + return true; + } + + bool valid=true; + Variant::evaluate(op->op,a,b,r_ret,valid); + if (!valid) { + r_error_str="Invalid operands to operator "+Variant::get_operator_name(op->op)+": "+Variant::get_type_name(a.get_type())+" and "+Variant::get_type_name(b.get_type())+"."; + return true; + } + + } break; + case VisualScriptExpression::ENode::TYPE_INDEX: { + + const VisualScriptExpression::IndexNode *index = static_cast<const VisualScriptExpression::IndexNode*>(p_node); + + Variant base; + bool ret = _execute(p_inputs,index->base,base,r_error_str,ce); + if (ret) + return true; + + Variant idx; + + ret = _execute(p_inputs,index->index,idx,r_error_str,ce); + if (ret) + return true; + + bool valid; + r_ret=base.get(idx,&valid); + if (!valid) { + r_error_str="Invalid index of type "+Variant::get_type_name(idx.get_type())+" for base of type "+Variant::get_type_name(base.get_type())+"."; + return true; + } + + + + } break; + case VisualScriptExpression::ENode::TYPE_NAMED_INDEX: { + + const VisualScriptExpression::NamedIndexNode *index = static_cast<const VisualScriptExpression::NamedIndexNode*>(p_node); + + Variant base; + bool ret = _execute(p_inputs,index->base,base,r_error_str,ce); + if (ret) + return true; + + bool valid; + r_ret=base.get_named(index->name,&valid); + if (!valid) { + r_error_str="Invalid index '"+String(index->name)+"' for base of type "+Variant::get_type_name(base.get_type())+"."; + return true; + } + + } break; + case VisualScriptExpression::ENode::TYPE_ARRAY: { + const VisualScriptExpression::ArrayNode *array = static_cast<const VisualScriptExpression::ArrayNode*>(p_node); + + Array arr; + arr.resize(array->array.size()); + for (int i=0;i<array->array.size();i++) { + + Variant value; + bool ret = _execute(p_inputs,array->array[i],value,r_error_str,ce); + if (ret) + return true; + arr[i]=value; + } + + r_ret=arr; + + } break; + case VisualScriptExpression::ENode::TYPE_DICTIONARY: { + const VisualScriptExpression::DictionaryNode *dictionary = static_cast<const VisualScriptExpression::DictionaryNode*>(p_node); + + Dictionary d; + for (int i=0;i<dictionary->dict.size();i+=2) { + + Variant key; + bool ret = _execute(p_inputs,dictionary->dict[i+0],key,r_error_str,ce); + if (ret) + return true; + + Variant value; + ret = _execute(p_inputs,dictionary->dict[i+1],value,r_error_str,ce); + if (ret) + return true; + + d[key]=value; + } + + r_ret=d; + } break; + case VisualScriptExpression::ENode::TYPE_CONSTRUCTOR: { + + const VisualScriptExpression::ConstructorNode *constructor = static_cast<const VisualScriptExpression::ConstructorNode*>(p_node); + + Vector<Variant> arr; + Vector<const Variant*> argp; + arr.resize(constructor->arguments.size()); + argp.resize(constructor->arguments.size()); + + for (int i=0;i<constructor->arguments.size();i++) { + + Variant value; + bool ret = _execute(p_inputs,constructor->arguments[i],value,r_error_str,ce); + if (ret) + return true; + arr[i]=value; + argp[i]=&arr[i]; + } + + + r_ret=Variant::construct(constructor->data_type,argp.ptr(),argp.size(),ce); + + if (ce.error!=Variant::CallError::CALL_OK) { + r_error_str="Invalid arguments to construct '"+Variant::get_type_name(constructor->data_type)+"'."; + return true; + } + + + } break; + case VisualScriptExpression::ENode::TYPE_BUILTIN_FUNC: { + + const VisualScriptExpression::BuiltinFuncNode *bifunc = static_cast<const VisualScriptExpression::BuiltinFuncNode*>(p_node); + + Vector<Variant> arr; + Vector<const Variant*> argp; + arr.resize(bifunc->arguments.size()); + argp.resize(bifunc->arguments.size()); + + for (int i=0;i<bifunc->arguments.size();i++) { + + Variant value; + bool ret = _execute(p_inputs,bifunc->arguments[i],value,r_error_str,ce); + if (ret) + return true; + arr[i]=value; + argp[i]=&arr[i]; + } + + + VisualScriptBuiltinFunc::exec_func(bifunc->func,argp.ptr(),&r_ret,ce,r_error_str); + + if (ce.error!=Variant::CallError::CALL_OK) { + r_error_str="Builtin Call Failed. "+r_error_str; + return true; + } + + } break; + case VisualScriptExpression::ENode::TYPE_CALL: { + + const VisualScriptExpression::CallNode *call = static_cast<const VisualScriptExpression::CallNode*>(p_node); + + + Variant base; + bool ret = _execute(p_inputs,call->base,base,r_error_str,ce); + if (ret) + return true; + + Vector<Variant> arr; + Vector<const Variant*> argp; + arr.resize(call->arguments.size()); + argp.resize(call->arguments.size()); + + for (int i=0;i<call->arguments.size();i++) { + + Variant value; + bool ret = _execute(p_inputs,call->arguments[i],value,r_error_str,ce); + if (ret) + return true; + arr[i]=value; + argp[i]=&arr[i]; + } + + + r_ret=base.call(call->method,argp.ptr(),argp.size(),ce); + + if (ce.error!=Variant::CallError::CALL_OK) { + r_error_str="On call to '"+String(call->method)+"':"; + return true; + } + + } break; + } + 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 (!expression->root || expression->error_set) { + r_error_str=expression->error_str; + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + return 0; + } + + + bool error = _execute(p_inputs,expression->root,*p_outputs[0],r_error_str,r_error); + if (error && r_error.error==Variant::CallError::CALL_OK) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + } + +#ifdef DEBUG_ENABLED + if (!error && expression->output_type!=Variant::NIL && !Variant::can_convert_strict(p_outputs[0]->get_type(),expression->output_type)) { + + r_error_str+="Can't convert expression result from "+Variant::get_type_name(p_outputs[0]->get_type())+" to "+Variant::get_type_name(expression->output_type)+"."; + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + + } +#endif + + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptExpression::instance(VisualScriptInstance* p_instance){ + + _compile_expression(); + VisualScriptNodeInstanceExpression *instance = memnew( VisualScriptNodeInstanceExpression ); + instance->instance=p_instance; + instance->expression=this; + return instance; +} + + +VisualScriptExpression::VisualScriptExpression() +{ + output_type=Variant::NIL; + expression_dirty=true; + error_set=true; + root=NULL; + nodes=NULL; + sequenced=false; +} + +VisualScriptExpression::~VisualScriptExpression() { + + if (nodes) { + memdelete(nodes); + } +} + + +void register_visual_script_expression_node() { + + VisualScriptLanguage::singleton->add_register_func("operators/expression",create_node_generic<VisualScriptExpression>); + +} diff --git a/modules/visual_script/visual_script_expression.h b/modules/visual_script/visual_script_expression.h new file mode 100644 index 0000000000..4edae133c7 --- /dev/null +++ b/modules/visual_script/visual_script_expression.h @@ -0,0 +1,280 @@ +#ifndef VISUALSCRIPTEXPRESSION_H +#define VISUALSCRIPTEXPRESSION_H + +#include "visual_script.h" +#include "visual_script_builtin_funcs.h" + +class VisualScriptExpression : public VisualScriptNode { + + OBJ_TYPE(VisualScriptExpression,VisualScriptNode) +friend class VisualScriptNodeInstanceExpression; + + struct Input { + + Variant::Type type; + String name; + + Input() { type=Variant::NIL; } + }; + + Vector<Input> inputs; + Variant::Type output_type; + + String expression; + + bool sequenced; + int str_ofs; + bool expression_dirty; + + bool _compile_expression(); + + enum TokenType { + TK_CURLY_BRACKET_OPEN, + TK_CURLY_BRACKET_CLOSE, + TK_BRACKET_OPEN, + TK_BRACKET_CLOSE, + TK_PARENTHESIS_OPEN, + TK_PARENTHESIS_CLOSE, + TK_IDENTIFIER, + TK_BUILTIN_FUNC, + TK_SELF, + TK_CONSTANT, + TK_BASIC_TYPE, + TK_COLON, + TK_COMMA, + TK_PERIOD, + TK_OP_IN, + TK_OP_EQUAL, + TK_OP_NOT_EQUAL, + TK_OP_LESS, + TK_OP_LESS_EQUAL, + TK_OP_GREATER, + TK_OP_GREATER_EQUAL, + TK_OP_AND, + TK_OP_OR, + TK_OP_NOT, + TK_OP_ADD, + TK_OP_SUB, + TK_OP_MUL, + TK_OP_DIV, + TK_OP_MOD, + TK_OP_SHIFT_LEFT, + TK_OP_SHIFT_RIGHT, + TK_OP_BIT_AND, + TK_OP_BIT_OR, + TK_OP_BIT_XOR, + TK_OP_BIT_INVERT, + TK_EOF, + TK_ERROR, + TK_MAX + }; + + static const char* token_name[TK_MAX]; + struct Token { + + TokenType type; + Variant value; + }; + + + void _set_error(const String& p_err) { + if (error_set) + return; + error_str=p_err; + error_set=true; + } + + Error _get_token(Token& r_token); + + String error_str; + bool error_set; + + + + struct ENode { + + enum Type { + TYPE_INPUT, + TYPE_CONSTANT, + TYPE_SELF, + TYPE_OPERATOR, + TYPE_INDEX, + TYPE_NAMED_INDEX, + TYPE_ARRAY, + TYPE_DICTIONARY, + TYPE_CONSTRUCTOR, + TYPE_BUILTIN_FUNC, + TYPE_CALL + }; + + ENode *next; + + Type type; + + ENode() { next=NULL; } + virtual ~ENode() { if (next) { memdelete(next); } } + }; + + struct Expression { + + bool is_op; + union { + Variant::Operator op; + ENode *node; + }; + }; + + ENode* _parse_expression(); + + struct InputNode : public ENode { + + int index; + InputNode() { + type=TYPE_INPUT; + } + }; + + + struct ConstantNode : public ENode { + + Variant value; + ConstantNode() { + type=TYPE_CONSTANT; + } + }; + + struct OperatorNode : public ENode { + + Variant::Operator op; + + ENode* nodes[2]; + + OperatorNode() { + type=TYPE_OPERATOR; + } + }; + + struct SelfNode : public ENode { + + + SelfNode() { + type=TYPE_SELF; + } + }; + + struct IndexNode : public ENode { + ENode*base; + ENode*index; + + IndexNode() { + type=TYPE_INDEX; + } + }; + + struct NamedIndexNode : public ENode { + ENode*base; + StringName name; + + NamedIndexNode() { + type=TYPE_NAMED_INDEX; + } + + }; + + struct ConstructorNode : public ENode { + Variant::Type data_type; + Vector<ENode*> arguments; + + ConstructorNode() { + type=TYPE_CONSTRUCTOR; + } + }; + + struct CallNode : public ENode { + ENode*base; + StringName method; + Vector<ENode*> arguments; + + CallNode() { + type=TYPE_CALL; + } + + }; + + struct ArrayNode : public ENode { + Vector<ENode*> array; + ArrayNode() { + type=TYPE_ARRAY; + } + + }; + + struct DictionaryNode : public ENode { + Vector<ENode*> dict; + DictionaryNode() { + type=TYPE_DICTIONARY; + } + + }; + + struct BuiltinFuncNode : public ENode { + VisualScriptBuiltinFunc::BuiltinFunc func; + Vector<ENode*> arguments; + BuiltinFuncNode() { + type=TYPE_BUILTIN_FUNC; + } + }; + + template<class T> + T* alloc_node() { + T* node = memnew(T); + node->next=nodes; + nodes=node; + return node; + } + + ENode *root; + ENode *nodes; + + + + + +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 "operators"; } + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptExpression(); + ~VisualScriptExpression(); +}; + + +void register_visual_script_expression_node(); + + +#endif // VISUALSCRIPTEXPRESSION_H diff --git a/modules/visual_script/visual_script_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp index cb0ff4086c..97338da187 100644 --- a/modules/visual_script/visual_script_flow_control.cpp +++ b/modules/visual_script/visual_script_flow_control.cpp @@ -2,6 +2,7 @@ #include "os/keyboard.h" #include "globals.h" + ////////////////////////////////////////// ////////////////RETURN//////////////////// ////////////////////////////////////////// @@ -85,7 +86,7 @@ void VisualScriptReturn::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_enable_return_value","enable"),&VisualScriptReturn::set_enable_return_value); ObjectTypeDB::bind_method(_MD("is_return_value_enabled"),&VisualScriptReturn::is_return_value_enabled); - String argt="Variant"; + String argt="Any"; for(int i=1;i<Variant::VARIANT_MAX;i++) { argt+=","+Variant::get_type_name(Variant::Type(i)); } @@ -152,7 +153,7 @@ static Ref<VisualScriptNode> create_return_node(const String& p_name) { int VisualScriptCondition::get_output_sequence_port_count() const { - return 2; + return 3; } bool VisualScriptCondition::has_input_sequence_port() const{ @@ -173,8 +174,10 @@ String VisualScriptCondition::get_output_sequence_port_text(int p_port) const { if (p_port==0) return "true"; - else + else if (p_port==1) return "false"; + else + return "done"; } PropertyInfo VisualScriptCondition::get_input_value_port_info(int p_idx) const{ @@ -217,10 +220,12 @@ public: 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; + if (p_start_mode==START_MODE_CONTINUE_SEQUENCE) + return 2; + else if (p_inputs[0]->operator bool()) + return 0 | STEP_FLAG_PUSH_STACK_BIT; else - return 1; + return 1 | STEP_FLAG_PUSH_STACK_BIT; } @@ -598,70 +603,64 @@ VisualScriptSequence::VisualScriptSequence() { ////////////////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 { +int VisualScriptSwitch::get_output_sequence_port_count() const { - return InputEvent::TYPE_MAX; + return case_values.size()+1; } -bool VisualScriptInputSelector::has_input_sequence_port() const{ +bool VisualScriptSwitch::has_input_sequence_port() const{ return true; } -int VisualScriptInputSelector::get_input_value_port_count() const{ +int VisualScriptSwitch::get_input_value_port_count() const{ - return 1; + return case_values.size()+1; } -int VisualScriptInputSelector::get_output_value_port_count() const{ +int VisualScriptSwitch::get_output_value_port_count() const{ - return 1; + return 0; } -String VisualScriptInputSelector::get_output_sequence_port_text(int p_port) const { +String VisualScriptSwitch::get_output_sequence_port_text(int p_port) const { + + if (p_port==case_values.size()) + return "done"; - return event_type_names[p_port]; + return String(); } -PropertyInfo VisualScriptInputSelector::get_input_value_port_info(int p_idx) const{ +PropertyInfo VisualScriptSwitch::get_input_value_port_info(int p_idx) const{ - return PropertyInfo(Variant::INPUT_EVENT,"event"); + if (p_idx<case_values.size()) { + return PropertyInfo(case_values[p_idx].type," ="); + } else + return PropertyInfo(Variant::NIL,"input"); } -PropertyInfo VisualScriptInputSelector::get_output_value_port_info(int p_idx) const{ +PropertyInfo VisualScriptSwitch::get_output_value_port_info(int p_idx) const{ - return PropertyInfo(Variant::INPUT_EVENT,""); + return PropertyInfo(); } -String VisualScriptInputSelector::get_caption() const { +String VisualScriptSwitch::get_caption() const { - return "InputSelector"; + return "Switch"; } -String VisualScriptInputSelector::get_text() const { +String VisualScriptSwitch::get_text() const { - return ""; + return "'input' is:"; } -class VisualScriptNodeInstanceInputSelector : public VisualScriptNodeInstance { +class VisualScriptNodeInstanceSwitch : public VisualScriptNodeInstance { public: VisualScriptInstance* instance; - InputEvent::Type type; + int case_count; //virtual int get_working_memory_size() const { return 0; } //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } @@ -669,37 +668,95 @@ public: 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; + if (p_start_mode==START_MODE_CONTINUE_SEQUENCE) { + return case_count; //exit } - InputEvent event = *p_inputs[0]; + for(int i=0;i<case_count;i++) { - *p_outputs[0] = event; + if (*p_inputs[i]==*p_inputs[case_count]) { + return i|STEP_FLAG_PUSH_STACK_BIT; + } + } - return event.type; + return case_count; } }; -VisualScriptNodeInstance* VisualScriptInputSelector::instance(VisualScriptInstance* p_instance) { +VisualScriptNodeInstance* VisualScriptSwitch::instance(VisualScriptInstance* p_instance) { - VisualScriptNodeInstanceInputSelector * instance = memnew(VisualScriptNodeInstanceInputSelector ); + VisualScriptNodeInstanceSwitch * instance = memnew(VisualScriptNodeInstanceSwitch ); instance->instance=p_instance; + instance->case_count=case_values.size(); return instance; } +bool VisualScriptSwitch::_set(const StringName& p_name, const Variant& p_value) { + if (String(p_name)=="case_count") { + case_values.resize(p_value); + _change_notify(); + ports_changed_notify(); + return true; + } -void VisualScriptInputSelector::_bind_methods() { + if (String(p_name).begins_with("case/")) { + int idx = String(p_name).get_slice("/",1).to_int(); + ERR_FAIL_INDEX_V(idx,case_values.size(),false); + case_values[idx].type=Variant::Type(int(p_value)); + _change_notify(); + ports_changed_notify(); + + return true; + } + + return false; } -VisualScriptInputSelector::VisualScriptInputSelector() { +bool VisualScriptSwitch::_get(const StringName& p_name,Variant &r_ret) const { + + if (String(p_name)=="case_count") { + r_ret=case_values.size(); + return true; + } + + if (String(p_name).begins_with("case/")) { + + int idx = String(p_name).get_slice("/",1).to_int(); + ERR_FAIL_INDEX_V(idx,case_values.size(),false); + + r_ret=case_values[idx].type; + return true; + } + + return false; + +} +void VisualScriptSwitch::_get_property_list( List<PropertyInfo> *p_list) const { + + p_list->push_back(PropertyInfo(Variant::INT,"case_count",PROPERTY_HINT_RANGE,"0,128")); + + String argt="Any"; + for(int i=1;i<Variant::VARIANT_MAX;i++) { + argt+=","+Variant::get_type_name(Variant::Type(i)); + } + + for(int i=0;i<case_values.size();i++) { + p_list->push_back(PropertyInfo(Variant::INT,"case/"+itos(i),PROPERTY_HINT_ENUM,argt)); + } +} + + +void VisualScriptSwitch::_bind_methods() { + + +} + +VisualScriptSwitch::VisualScriptSwitch() { } @@ -1354,6 +1411,19 @@ bool VisualScriptInputFilter::_get(const StringName& p_name,Variant &r_ret) cons } return false; } + +static const char* event_type_names[InputEvent::TYPE_MAX]={ + "None", + "Key", + "MouseMotion", + "MouseButton", + "JoystickMotion", + "JoystickButton", + "ScreenTouch", + "ScreenDrag", + "Action" +}; + void VisualScriptInputFilter::_get_property_list( List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::INT,"filter_count",PROPERTY_HINT_RANGE,"0,64")); @@ -1660,6 +1730,197 @@ VisualScriptInputFilter::VisualScriptInputFilter() { } +////////////////////////////////////////// +////////////////TYPE CAST/////////// +////////////////////////////////////////// + + +int VisualScriptTypeCast::get_output_sequence_port_count() const { + + return 2; +} + +bool VisualScriptTypeCast::has_input_sequence_port() const{ + + return true; +} + +int VisualScriptTypeCast::get_input_value_port_count() const{ + + + return 1; +} +int VisualScriptTypeCast::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptTypeCast::get_output_sequence_port_text(int p_port) const { + + return p_port==0 ? "yes" : "no"; +} + +PropertyInfo VisualScriptTypeCast::get_input_value_port_info(int p_idx) const{ + + return PropertyInfo(Variant::OBJECT,"instance"); +} + +PropertyInfo VisualScriptTypeCast::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(Variant::OBJECT,""); +} + + +String VisualScriptTypeCast::get_caption() const { + + return "TypeCast"; +} + +String VisualScriptTypeCast::get_text() const { + + if (script!=String()) + return "Is "+script.get_file()+"?"; + else + return "Is "+base_type+"?"; +} + +void VisualScriptTypeCast::set_base_type(const StringName& p_type) { + + if (base_type==p_type) + return; + + base_type=p_type; + _change_notify(); + ports_changed_notify(); +} + +StringName VisualScriptTypeCast::get_base_type() const{ + + return base_type; +} + +void VisualScriptTypeCast::set_base_script(const String& p_path){ + + if (script==p_path) + return; + + script=p_path; + _change_notify(); + ports_changed_notify(); + +} +String VisualScriptTypeCast::get_base_script() const{ + + return script; +} + + +class VisualScriptNodeInstanceTypeCast : public VisualScriptNodeInstance { +public: + + VisualScriptInstance* instance; + StringName base_type; + String script; + + //virtual int get_working_memory_size() const { return 0; } + //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } + //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + Object *obj = *p_inputs[0]; + + *p_outputs[0]=Variant(); + + if (!obj) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Instance is null"; + return 0; + } + + if (script!=String()) { + + Ref<Script> obj_script = obj->get_script(); + if (!obj_script.is_valid()) { + return 1; //well, definitely not the script because object we got has no script. + } + + if (!ResourceCache::has(script)) { + //if the script is not in use by anyone, we can safely assume whathever we got is not casting to it. + return 1; + } + Ref<Script> cast_script = Ref<Resource>(ResourceCache::get(script)); + if (!cast_script.is_valid()) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Script path is not a script: "+script; + return 1; + } + + while(obj_script.is_valid()) { + + if (cast_script==obj_script) { + *p_outputs[0]=*p_inputs[0]; //copy + return 0; // it is the script, yey + } + + obj_script=obj_script->get_base_script(); + } + + return 1; //not found sorry + } + + if (ObjectTypeDB::is_type(obj->get_type_name(),base_type)) { + *p_outputs[0]=*p_inputs[0]; //copy + return 0; + } else + return 1; + + } + + +}; + +VisualScriptNodeInstance* VisualScriptTypeCast::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceTypeCast * instance = memnew(VisualScriptNodeInstanceTypeCast ); + instance->instance=p_instance; + instance->base_type=base_type; + instance->script=script; + return instance; +} + + + +void VisualScriptTypeCast::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_base_type","type"),&VisualScriptTypeCast::set_base_type); + ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptTypeCast::get_base_type); + + ObjectTypeDB::bind_method(_MD("set_base_script","path"),&VisualScriptTypeCast::set_base_script); + ObjectTypeDB::bind_method(_MD("get_base_script"),&VisualScriptTypeCast::get_base_script); + + + List<String> script_extensions; + for(int i=0;i>ScriptServer::get_language_count();i++) { + ScriptServer::get_language(i)->get_recognized_extensions(&script_extensions); + } + + String script_ext_hint; + for (List<String>::Element *E=script_extensions.front();E;E=E->next()) { + if (script_ext_hint!=String()) + script_ext_hint+=","; + script_ext_hint+="*."+E->get(); + } + + ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type")); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"property/base_script",PROPERTY_HINT_FILE,script_ext_hint),_SCS("set_base_script"),_SCS("get_base_script")); + +} + +VisualScriptTypeCast::VisualScriptTypeCast() { + + base_type="Object"; +} void register_visual_script_flow_control_nodes() { @@ -1670,8 +1931,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/switch",create_node_generic<VisualScriptSwitch>); VisualScriptLanguage::singleton->add_register_func("flow_control/input_filter",create_node_generic<VisualScriptInputFilter>); + VisualScriptLanguage::singleton->add_register_func("flow_control/type_cast",create_node_generic<VisualScriptTypeCast>); diff --git a/modules/visual_script/visual_script_flow_control.h b/modules/visual_script/visual_script_flow_control.h index ed0e328629..e0da84a534 100644 --- a/modules/visual_script/visual_script_flow_control.h +++ b/modules/visual_script/visual_script_flow_control.h @@ -197,14 +197,24 @@ public: -class VisualScriptInputSelector : public VisualScriptNode { +class VisualScriptSwitch : public VisualScriptNode { - OBJ_TYPE(VisualScriptInputSelector,VisualScriptNode) + OBJ_TYPE(VisualScriptSwitch,VisualScriptNode) + struct Case { + Variant::Type type; + Case() { type=Variant::NIL; } + }; + Vector<Case> case_values; +friend class VisualScriptNodeInstanceSwitch; 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; + static void _bind_methods(); public: @@ -213,6 +223,7 @@ public: virtual String get_output_sequence_port_text(int p_port) const; + virtual bool has_mixed_input_and_sequence_ports() const { return true; } virtual int get_input_value_port_count() const; @@ -229,7 +240,7 @@ public: virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); - VisualScriptInputSelector(); + VisualScriptSwitch(); }; @@ -273,6 +284,56 @@ public: VisualScriptInputFilter(); }; + + + + +class VisualScriptTypeCast : public VisualScriptNode { + + OBJ_TYPE(VisualScriptTypeCast,VisualScriptNode) + + + StringName base_type; + String script; + +protected: + + static void _bind_methods(); +public: + + virtual int get_output_sequence_port_count() const; + virtual bool has_input_sequence_port() const; + + + virtual String get_output_sequence_port_text(int p_port) const; + + + virtual int get_input_value_port_count() const; + virtual int get_output_value_port_count() const; + + + virtual PropertyInfo get_input_value_port_info(int p_idx) const; + virtual PropertyInfo get_output_value_port_info(int p_idx) const; + + virtual String get_caption() const; + virtual String get_text() const; + virtual String get_category() const { return "flow_control"; } + + void set_base_type(const StringName& p_type); + StringName get_base_type() const; + + void set_base_script(const String& p_path); + String get_base_script() const; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + + VisualScriptTypeCast(); +}; + + + + void register_visual_script_flow_control_nodes(); diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp index 12bc395474..5a21cb40e9 100644 --- a/modules/visual_script/visual_script_func_nodes.cpp +++ b/modules/visual_script/visual_script_func_nodes.cpp @@ -3,6 +3,8 @@ #include "os/os.h" #include "scene/main/node.h" #include "visual_script_nodes.h" +#include "io/resource_loader.h" +#include "globals.h" ////////////////////////////////////////// ////////////////CALL////////////////////// @@ -10,12 +12,18 @@ int VisualScriptFunctionCall::get_output_sequence_port_count() const { - return 1; + if (method_cache.flags&METHOD_FLAG_CONST || call_mode==CALL_MODE_BASIC_TYPE) + return 0; + else + return 1; } bool VisualScriptFunctionCall::has_input_sequence_port() const{ - return true; + if (method_cache.flags&METHOD_FLAG_CONST || call_mode==CALL_MODE_BASIC_TYPE) + return false; + else + return true; } #ifdef TOOLS_ENABLED @@ -91,20 +99,23 @@ StringName VisualScriptFunctionCall::_get_base_type() const { return base_type; } + int VisualScriptFunctionCall::get_input_value_port_count() const{ if (call_mode==CALL_MODE_BASIC_TYPE) { Vector<StringName> names = Variant::get_method_argument_names(basic_type,function); - return names.size()+1; + return names.size() + (rpc_call_mode>=RPC_RELIABLE_TO_ID?1:0) + 1; } else { + MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function); - if (!mb) - return 0; + if (mb) { + return mb->get_argument_count() + (call_mode==CALL_MODE_INSTANCE?1:0) + (rpc_call_mode>=RPC_RELIABLE_TO_ID?1:0) - use_default_args; + } - return mb->get_argument_count() + (call_mode==CALL_MODE_INSTANCE?1:0) - use_default_args; + return method_cache.arguments.size() + (call_mode==CALL_MODE_INSTANCE?1:0) + (rpc_call_mode>=RPC_RELIABLE_TO_ID?1:0) - use_default_args; } } @@ -117,11 +128,18 @@ int VisualScriptFunctionCall::get_output_value_port_count() const{ return returns?1:0; } else { + int ret; MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function); - if (!mb) - return 0; + if (mb) { + ret = mb->has_return() ? 1 : 0; + } else + ret = 1; //it is assumed that script always returns something + + if (call_mode==CALL_MODE_INSTANCE) { + ret++; + } - return mb->has_return() ? 1 : 0; + return ret; } } @@ -143,6 +161,16 @@ PropertyInfo VisualScriptFunctionCall::get_input_value_port_info(int p_idx) cons } } + if (rpc_call_mode>=RPC_RELIABLE_TO_ID) { + + if (p_idx==0) { + return PropertyInfo(Variant::INT,"peer_id"); + } else { + p_idx--; + } + + } + #ifdef DEBUG_METHODS_ENABLED if (call_mode==CALL_MODE_BASIC_TYPE) { @@ -155,10 +183,15 @@ PropertyInfo VisualScriptFunctionCall::get_input_value_port_info(int p_idx) cons } else { MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function); - if (!mb) - return PropertyInfo(); + if (mb) { + return mb->get_argument_info(p_idx); + } + + if (p_idx>=0 && p_idx < method_cache.arguments.size()) { + return method_cache.arguments[p_idx]; + } - return mb->get_argument_info(p_idx); + return PropertyInfo(); } #else return PropertyInfo(); @@ -177,13 +210,34 @@ PropertyInfo VisualScriptFunctionCall::get_output_value_port_info(int p_idx) con return PropertyInfo(Variant::get_method_return_type(basic_type,function),""); } else { - MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function); - if (!mb) - return PropertyInfo(); + if (call_mode==CALL_MODE_INSTANCE) { + if (p_idx==0) { + return PropertyInfo(Variant::OBJECT,"pass"); + } else { + p_idx--; + } + } + + PropertyInfo ret; + + /*MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function); + if (mb) { + + ret = mb->get_argument_info(-1); + } else {*/ + + ret = method_cache.return_val; + + //} + + if (call_mode==CALL_MODE_INSTANCE) { + ret.name="return"; + } else { + ret.name=""; + } + return ret; + - PropertyInfo pi = mb->get_argument_info(-1); - pi.name=""; - return pi; } #else return PropertyInfo(); @@ -193,59 +247,38 @@ PropertyInfo VisualScriptFunctionCall::get_output_value_port_info(int p_idx) con String VisualScriptFunctionCall::get_caption() const { - static const char*cname[4]= { + static const char*cname[5]= { "CallSelf", "CallNode", "CallInstance", - "CallBasic" + "CallBasic", + "CallSingleton" }; - return cname[call_mode]; + String caption = cname[call_mode]; + + if (rpc_call_mode) { + caption+=" (RPC)"; + } + + return caption; } String VisualScriptFunctionCall::get_text() const { if (call_mode==CALL_MODE_SELF) return " "+String(function)+"()"; + if (call_mode==CALL_MODE_SINGLETON) + return String(singleton)+":"+String(function)+"()"; else if (call_mode==CALL_MODE_BASIC_TYPE) return Variant::get_type_name(basic_type)+"."+String(function)+"()"; + else if (call_mode==CALL_MODE_NODE_PATH) + return " ["+String(base_path.simplified())+"]."+String(function)+"()"; else return " "+base_type+"."+String(function)+"()"; } -void VisualScriptFunctionCall::_update_defargs() { - - //save base type if accessible - - if (call_mode==CALL_MODE_NODE_PATH) { - - Node* node=_get_base_node(); - if (node) { - base_type=node->get_type(); - } - } else if (call_mode==CALL_MODE_SELF) { - - if (get_visual_script().is_valid()) { - base_type=get_visual_script()->get_instance_base_type(); - } - } - - - if (call_mode==CALL_MODE_BASIC_TYPE) { - use_default_args = Variant::get_method_default_arguments(basic_type,function).size(); - } else { - if (!get_visual_script().is_valid()) - return; //do not change if not valid yet - - MethodBind *mb = ObjectTypeDB::get_method(_get_base_type(),function); - if (!mb) - return; - - use_default_args=mb->get_default_argument_count(); - } - -} void VisualScriptFunctionCall::set_basic_type(Variant::Type p_type) { @@ -253,7 +286,7 @@ void VisualScriptFunctionCall::set_basic_type(Variant::Type p_type) { return; basic_type=p_type; - _update_defargs(); + _change_notify(); ports_changed_notify(); } @@ -269,7 +302,6 @@ void VisualScriptFunctionCall::set_base_type(const StringName& p_type) { return; base_type=p_type; - _update_defargs(); _change_notify(); ports_changed_notify(); } @@ -279,13 +311,144 @@ StringName VisualScriptFunctionCall::get_base_type() const{ return base_type; } +void VisualScriptFunctionCall::set_base_script(const String& p_path) { + + if (base_script==p_path) + return; + + base_script=p_path; + _change_notify(); + ports_changed_notify(); +} + +String VisualScriptFunctionCall::get_base_script() const { + + return base_script; +} + +void VisualScriptFunctionCall::set_singleton(const StringName& p_path) { + + if (singleton==p_path) + return; + + singleton=p_path; + Object *obj = Globals::get_singleton()->get_singleton_object(singleton); + if (obj) { + base_type=obj->get_type(); + } + + _change_notify(); + ports_changed_notify(); +} + +StringName VisualScriptFunctionCall::get_singleton() const { + + return singleton; +} + + + +void VisualScriptFunctionCall::_update_method_cache() { + StringName type; + Ref<Script> script; + + if (call_mode==CALL_MODE_NODE_PATH) { + + Node* node=_get_base_node(); + if (node) { + type=node->get_type(); + base_type=type; //cache, too + script = node->get_script(); + } + } else if (call_mode==CALL_MODE_SELF) { + + if (get_visual_script().is_valid()) { + type=get_visual_script()->get_instance_base_type(); + base_type=type; //cache, too + script=get_visual_script(); + } + + } else if (call_mode==CALL_MODE_SINGLETON) { + + Object *obj = Globals::get_singleton()->get_singleton_object(singleton); + if (obj) { + type=obj->get_type(); + script=obj->get_script(); + } + + } else if (call_mode==CALL_MODE_INSTANCE) { + + type=base_type; + if (base_script!=String()) { + + if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) { + + ScriptServer::edit_request_func(base_script); //make sure it's loaded + } + + if (ResourceCache::has(base_script)) { + + script = Ref<Resource>( ResourceCache::get(base_script) ); + } else { + return; + } + } + } + + +// print_line("BASE: "+String(type)+" FUNC: "+String(function)); + MethodBind *mb = ObjectTypeDB::get_method(type,function); + if (mb) { + use_default_args=mb->get_default_argument_count(); + method_cache = MethodInfo(); + for(int i=0;i<mb->get_argument_count();i++) { +#ifdef DEBUG_METHODS_ENABLED + method_cache.arguments.push_back(mb->get_argument_info(i)); +#else + method_cache.arguments.push_back(PropertyInfo()); +#endif + } + + if (mb->is_const()) { + method_cache.flags|=METHOD_FLAG_CONST; + } + +#ifdef DEBUG_METHODS_ENABLED + + method_cache.return_val = mb->get_argument_info(-1); +#endif + + if (mb->is_vararg()) { + //for vararg just give it 10 arguments (should be enough for most use cases) + for(int i=0;i<10;i++) { + method_cache.arguments.push_back(PropertyInfo(Variant::NIL,"arg"+itos(i))); + use_default_args++; + } + } + } else if (script.is_valid() && script->has_method(function)) { + + method_cache = script->get_method_info(function); + use_default_args=method_cache.default_arguments.size(); + } +} + void VisualScriptFunctionCall::set_function(const StringName& p_type){ if (function==p_type) return; function=p_type; - _update_defargs(); + + if (call_mode==CALL_MODE_BASIC_TYPE) { + use_default_args = Variant::get_method_default_arguments(basic_type,function).size(); + } else { + //update all caches + + _update_method_cache(); + + } + + _change_notify(); ports_changed_notify(); } @@ -301,7 +464,6 @@ void VisualScriptFunctionCall::set_base_path(const NodePath& p_type) { return; base_path=p_type; - _update_defargs(); _change_notify(); ports_changed_notify(); } @@ -318,7 +480,6 @@ void VisualScriptFunctionCall::set_call_mode(CallMode p_mode) { return; call_mode=p_mode; - _update_defargs(); _change_notify(); ports_changed_notify(); @@ -339,10 +500,49 @@ void VisualScriptFunctionCall::set_use_default_args(int p_amount) { } +void VisualScriptFunctionCall::set_rpc_call_mode(VisualScriptFunctionCall::RPCCallMode p_mode) { + + if (rpc_call_mode==p_mode) + return; + rpc_call_mode=p_mode; + ports_changed_notify(); + _change_notify(); +} + +VisualScriptFunctionCall::RPCCallMode VisualScriptFunctionCall::get_rpc_call_mode() const{ + + return rpc_call_mode; +} + + int VisualScriptFunctionCall::get_use_default_args() const{ return use_default_args; } + + +void VisualScriptFunctionCall::set_validate(bool p_amount) { + + validate=p_amount; +} + +bool VisualScriptFunctionCall::get_validate() const { + + return validate; +} + + +void VisualScriptFunctionCall::_set_argument_cache(const Dictionary& p_cache) { + //so everything works in case all else fails + method_cache=MethodInfo::from_dict(p_cache); + +} + +Dictionary VisualScriptFunctionCall::_get_argument_cache() const { + + return method_cache; +} + void VisualScriptFunctionCall::_validate_property(PropertyInfo& property) const { if (property.name=="function/base_type") { @@ -351,12 +551,36 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo& property) const } } + if (property.name=="function/base_script") { + if (call_mode!=CALL_MODE_INSTANCE) { + property.usage=0; + } + } + if (property.name=="function/basic_type") { if (call_mode!=CALL_MODE_BASIC_TYPE) { property.usage=0; } } + if (property.name=="function/singleton") { + if (call_mode!=CALL_MODE_SINGLETON) { + property.usage=0; + } else { + List<Globals::Singleton> names; + Globals::get_singleton()->get_singletons(&names); + property.hint=PROPERTY_HINT_ENUM; + String sl; + for (List<Globals::Singleton>::Element *E=names.front();E;E=E->next()) { + if (sl!=String()) + sl+=","; + sl+=E->get().name; + } + property.hint_string=sl; + + } + } + if (property.name=="function/node_path") { if (call_mode!=CALL_MODE_NODE_PATH) { property.usage=0; @@ -381,9 +605,38 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo& property) const } else if (call_mode==CALL_MODE_SELF && get_visual_script().is_valid()) { property.hint=PROPERTY_HINT_METHOD_OF_SCRIPT; property.hint_string=itos(get_visual_script()->get_instance_ID()); + } else if (call_mode==CALL_MODE_SINGLETON) { + + Object *obj = Globals::get_singleton()->get_singleton_object(singleton); + if (obj) { + property.hint=PROPERTY_HINT_METHOD_OF_INSTANCE; + property.hint_string=itos(obj->get_instance_ID()); + } else { + + property.hint=PROPERTY_HINT_METHOD_OF_BASE_TYPE; + property.hint_string=base_type;//should be cached + } } else if (call_mode==CALL_MODE_INSTANCE) { property.hint=PROPERTY_HINT_METHOD_OF_BASE_TYPE; property.hint_string=base_type; + + if (base_script!=String()) { + if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) { + + ScriptServer::edit_request_func(base_script); //make sure it's loaded + } + + if (ResourceCache::has(base_script)) { + + Ref<Script> script = Ref<Resource>( ResourceCache::get(base_script) ); + if (script.is_valid()) { + + property.hint=PROPERTY_HINT_METHOD_OF_SCRIPT; + property.hint_string=itos(script->get_instance_ID()); + } + } + } + } else if (call_mode==CALL_MODE_NODE_PATH) { Node *node = _get_base_node(); if (node) { @@ -422,6 +675,13 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo& property) const property.hint_string="0,"+itos(mc)+",1"; } } + + if (property.name=="rpc/call_mode") { + if (call_mode==CALL_MODE_BASIC_TYPE) { + property.usage=0; + } + } + } @@ -430,9 +690,15 @@ void VisualScriptFunctionCall::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_base_type","base_type"),&VisualScriptFunctionCall::set_base_type); ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptFunctionCall::get_base_type); + ObjectTypeDB::bind_method(_MD("set_base_script","base_script"),&VisualScriptFunctionCall::set_base_script); + ObjectTypeDB::bind_method(_MD("get_base_script"),&VisualScriptFunctionCall::get_base_script); + ObjectTypeDB::bind_method(_MD("set_basic_type","basic_type"),&VisualScriptFunctionCall::set_basic_type); ObjectTypeDB::bind_method(_MD("get_basic_type"),&VisualScriptFunctionCall::get_basic_type); + ObjectTypeDB::bind_method(_MD("set_singleton","singleton"),&VisualScriptFunctionCall::set_singleton); + ObjectTypeDB::bind_method(_MD("get_singleton"),&VisualScriptFunctionCall::get_singleton); + ObjectTypeDB::bind_method(_MD("set_function","function"),&VisualScriptFunctionCall::set_function); ObjectTypeDB::bind_method(_MD("get_function"),&VisualScriptFunctionCall::get_function); @@ -445,6 +711,14 @@ void VisualScriptFunctionCall::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_use_default_args","amount"),&VisualScriptFunctionCall::set_use_default_args); ObjectTypeDB::bind_method(_MD("get_use_default_args"),&VisualScriptFunctionCall::get_use_default_args); + ObjectTypeDB::bind_method(_MD("_set_argument_cache","argument_cache"),&VisualScriptFunctionCall::_set_argument_cache); + ObjectTypeDB::bind_method(_MD("_get_argument_cache"),&VisualScriptFunctionCall::_get_argument_cache); + + ObjectTypeDB::bind_method(_MD("set_rpc_call_mode","mode"),&VisualScriptFunctionCall::set_rpc_call_mode); + ObjectTypeDB::bind_method(_MD("get_rpc_call_mode"),&VisualScriptFunctionCall::get_rpc_call_mode); + + ObjectTypeDB::bind_method(_MD("set_validate","enable"),&VisualScriptFunctionCall::set_validate); + ObjectTypeDB::bind_method(_MD("get_validate"),&VisualScriptFunctionCall::get_validate); String bt; for(int i=0;i<Variant::VARIANT_MAX;i++) { @@ -454,12 +728,32 @@ void VisualScriptFunctionCall::_bind_methods() { bt+=Variant::get_type_name(Variant::Type(i)); } - ADD_PROPERTY(PropertyInfo(Variant::INT,"function/call_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance,Basic Type"),_SCS("set_call_mode"),_SCS("get_call_mode")); + + List<String> script_extensions; + for(int i=0;i<ScriptServer::get_language_count();i++) { + ScriptServer::get_language(i)->get_recognized_extensions(&script_extensions); + } + + String script_ext_hint; + for (List<String>::Element *E=script_extensions.front();E;E=E->next()) { + if (script_ext_hint!=String()) + script_ext_hint+=","; + script_ext_hint+="*."+E->get(); + } + + + + ADD_PROPERTY(PropertyInfo(Variant::INT,"function/call_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance,Basic Type,Singleton"),_SCS("set_call_mode"),_SCS("get_call_mode")); ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type")); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/base_script",PROPERTY_HINT_FILE,script_ext_hint),_SCS("set_base_script"),_SCS("get_base_script")); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/singleton"),_SCS("set_singleton"),_SCS("get_singleton")); ADD_PROPERTY(PropertyInfo(Variant::INT,"function/basic_type",PROPERTY_HINT_ENUM,bt),_SCS("set_basic_type"),_SCS("get_basic_type")); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"function/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_base_path"),_SCS("get_base_path")); - ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/function"),_SCS("set_function"),_SCS("get_function")); + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY,"function/argument_cache",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_argument_cache"),_SCS("_get_argument_cache")); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"function/function"),_SCS("set_function"),_SCS("get_function")); //when set, if loaded properly, will override argument count. ADD_PROPERTY(PropertyInfo(Variant::INT,"function/use_default_args"),_SCS("set_use_default_args"),_SCS("get_use_default_args")); + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"function/validate"),_SCS("set_validate"),_SCS("get_validate")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"rpc/call_mode",PROPERTY_HINT_ENUM,"Disabled,Reliable,Unreliable,ReliableToID,UnreliableToID"),_SCS("set_rpc_call_mode"),_SCS("get_rpc_call_mode")); //when set, if loaded properly, will override argument count. BIND_CONSTANT( CALL_MODE_SELF ); BIND_CONSTANT( CALL_MODE_NODE_PATH); @@ -474,8 +768,11 @@ public: VisualScriptFunctionCall::CallMode call_mode; NodePath node_path; int input_args; + bool validate; bool returns; + VisualScriptFunctionCall::RPCCallMode rpc_mode; StringName function; + StringName singleton; VisualScriptFunctionCall *node; VisualScriptInstance *instance; @@ -486,6 +783,35 @@ public: //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; } + + _FORCE_INLINE_ bool call_rpc(Object* p_base,const Variant** p_args,int p_argcount) { + + if (!p_base) + return false; + + Node * node = p_base->cast_to<Node>(); + if (!node) + return false; + + int to_id=0; + bool reliable=true; + + if (rpc_mode>=VisualScriptFunctionCall::RPC_RELIABLE_TO_ID) { + to_id = *p_args[0]; + p_args+=1; + p_argcount-=1; + if (rpc_mode==VisualScriptFunctionCall::RPC_UNRELIABLE_TO_ID) { + reliable=false; + } + } else if (rpc_mode==VisualScriptFunctionCall::RPC_UNRELIABLE) { + reliable=false; + } + + node->rpcp(to_id,!reliable,function,p_args,p_argcount); + + 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) { @@ -495,7 +821,9 @@ public: Object *object=instance->get_owner_ptr(); - if (returns) { + if (rpc_mode) { + call_rpc(object,p_inputs,input_args); + } else if (returns) { *p_outputs[0] = object->call(function,p_inputs,input_args,r_error); } else { object->call(function,p_inputs,input_args,r_error); @@ -517,7 +845,9 @@ public: return 0; } - if (returns) { + if (rpc_mode) { + call_rpc(node,p_inputs,input_args); + } else if (returns) { *p_outputs[0] = another->call(function,p_inputs,input_args,r_error); } else { another->call(function,p_inputs,input_args,r_error); @@ -529,15 +859,53 @@ public: Variant v = *p_inputs[0]; - if (returns) { - *p_outputs[0] = v.call(function,p_inputs+1,input_args,r_error); + if (rpc_mode) { + Object *obj = v; + if (obj) { + call_rpc(obj,p_inputs+1,input_args-1); + } + } else if (returns) { + if (call_mode==VisualScriptFunctionCall::CALL_MODE_INSTANCE) { + *p_outputs[1] = v.call(function,p_inputs+1,input_args,r_error); + } else { + *p_outputs[0] = v.call(function,p_inputs+1,input_args,r_error); + } } else { v.call(function,p_inputs+1,input_args,r_error); } + if (call_mode==VisualScriptFunctionCall::CALL_MODE_INSTANCE) { + *p_outputs[0]=*p_inputs[0]; + } + + } break; + case VisualScriptFunctionCall::CALL_MODE_SINGLETON: { + + Object *object=Globals::get_singleton()->get_singleton_object(singleton); + if (!object) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Invalid singleton name: '"+String(singleton)+"'"; + return 0; + } + + if (rpc_mode) { + call_rpc(object,p_inputs,input_args); + } else 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; } + + if (!validate) { + + //ignore call errors if validation is disabled + r_error.error=Variant::CallError::CALL_OK; + r_error_str=String(); + } + return 0; } @@ -550,19 +918,37 @@ VisualScriptNodeInstance* VisualScriptFunctionCall::instance(VisualScriptInstanc VisualScriptNodeInstanceFunctionCall * instance = memnew(VisualScriptNodeInstanceFunctionCall ); instance->node=this; instance->instance=p_instance; + instance->singleton=singleton; 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 ); + instance->rpc_mode=rpc_call_mode; + instance->validate=validate; return instance; } + + +VisualScriptFunctionCall::TypeGuess VisualScriptFunctionCall::guess_output_type(TypeGuess* p_inputs, int p_output) const { + + if (p_output==0 && call_mode==CALL_MODE_INSTANCE) { + return p_inputs[0]; + } + + return VisualScriptNode::guess_output_type(p_inputs,p_output); + +} + VisualScriptFunctionCall::VisualScriptFunctionCall() { + validate=true; call_mode=CALL_MODE_SELF; basic_type=Variant::NIL; use_default_args=0; base_type="Object"; + rpc_call_mode=RPC_DISABLED; + } @@ -595,12 +981,12 @@ static const char* event_type_names[InputEvent::TYPE_MAX]={ int VisualScriptPropertySet::get_output_sequence_port_count() const { - return 1; + return call_mode!=CALL_MODE_BASIC_TYPE ? 1 : 0; } bool VisualScriptPropertySet::has_input_sequence_port() const{ - return true; + return call_mode!=CALL_MODE_BASIC_TYPE ? true : false; } Node *VisualScriptPropertySet::_get_base_node() const { @@ -657,16 +1043,13 @@ StringName VisualScriptPropertySet::_get_base_type() const { int VisualScriptPropertySet::get_input_value_port_count() const{ - int pc = (call_mode==CALL_MODE_BASIC_TYPE || call_mode==CALL_MODE_INSTANCE)?1:0; - - if (!use_builtin_value) - pc++; + int pc = (call_mode==CALL_MODE_BASIC_TYPE || call_mode==CALL_MODE_INSTANCE)?2:1; return pc; } int VisualScriptPropertySet::get_output_value_port_count() const{ - return call_mode==CALL_MODE_BASIC_TYPE? 1 : 0; + return (call_mode==CALL_MODE_BASIC_TYPE || call_mode==CALL_MODE_INSTANCE) ? 1 : 0; } String VisualScriptPropertySet::get_output_sequence_port_text(int p_port) const { @@ -687,60 +1070,16 @@ PropertyInfo VisualScriptPropertySet::get_input_value_port_info(int p_idx) const } } -#ifdef DEBUG_METHODS_ENABLED - - //not very efficient but.. - - - List<PropertyInfo> pinfo; - - if (call_mode==CALL_MODE_BASIC_TYPE) { - - - 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(); - if (n) { - n->get_property_list(&pinfo); - } else { - ObjectTypeDB::get_property_list(_get_base_type(),&pinfo); - } - } else { - ObjectTypeDB::get_property_list(_get_base_type(),&pinfo); - } - - - for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { - - if (E->get().name==property) { - - PropertyInfo info=E->get(); - info.name="value"; - return info; - } - } - - -#endif - - return PropertyInfo(Variant::NIL,"value"); - + PropertyInfo pinfo=type_cache; + pinfo.name="value"; + return pinfo; } PropertyInfo VisualScriptPropertySet::get_output_value_port_info(int p_idx) const{ if (call_mode==CALL_MODE_BASIC_TYPE) { return PropertyInfo(basic_type,"out"); + } else if (call_mode==CALL_MODE_INSTANCE) { + return PropertyInfo(Variant::OBJECT,"pass"); } else { return PropertyInfo(); } @@ -766,18 +1105,12 @@ String VisualScriptPropertySet::get_text() const { if (call_mode==CALL_MODE_BASIC_TYPE) prop=Variant::get_type_name(basic_type)+"."+property; - else + else if (call_mode==CALL_MODE_NODE_PATH) + prop=String(base_path)+":"+property; + else if (call_mode==CALL_MODE_SELF) prop=property; - - if (use_builtin_value) { - String bit = builtin_value.get_construct_string(); - if (bit.length()>40) { - bit=bit.substr(0,40); - bit+="..."; - } - - prop+="\n "+bit; - } + else if (call_mode==CALL_MODE_INSTANCE) + prop=String(base_type)+":"+property; return prop; @@ -821,6 +1154,9 @@ void VisualScriptPropertySet::set_event_type(InputEvent::Type p_type) { if (event_type==p_type) return; event_type=p_type; + if (call_mode==CALL_MODE_BASIC_TYPE) { + _update_cache(); + } _change_notify(); _update_base_type(); ports_changed_notify(); @@ -847,12 +1183,133 @@ StringName VisualScriptPropertySet::get_base_type() const{ return base_type; } + +void VisualScriptPropertySet::set_base_script(const String& p_path) { + + if (base_script==p_path) + return; + + base_script=p_path; + _change_notify(); + ports_changed_notify(); +} + +String VisualScriptPropertySet::get_base_script() const { + + return base_script; +} + + +void VisualScriptPropertySet::_update_cache() { + + + if (!OS::get_singleton()->get_main_loop()) + return; + if (!OS::get_singleton()->get_main_loop()->cast_to<SceneTree>()) + return; + + if (!OS::get_singleton()->get_main_loop()->cast_to<SceneTree>()->is_editor_hint()) //only update cache if editor exists, it's pointless otherwise + return; + + if (call_mode==CALL_MODE_BASIC_TYPE) { + + //not super efficient.. + + 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); + } + + List<PropertyInfo> pinfo; + v.get_property_list(&pinfo); + + for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { + + if (E->get().name==property) { + + type_cache=E->get(); + } + } + + } else { + + + StringName type; + Ref<Script> script; + Node *node=NULL; + + if (call_mode==CALL_MODE_NODE_PATH) { + + node=_get_base_node(); + if (node) { + type=node->get_type(); + base_type=type; //cache, too + script = node->get_script(); + } + } else if (call_mode==CALL_MODE_SELF) { + + if (get_visual_script().is_valid()) { + type=get_visual_script()->get_instance_base_type(); + base_type=type; //cache, too + script=get_visual_script(); + } + } else if (call_mode==CALL_MODE_INSTANCE) { + + type=base_type; + if (base_script!=String()) { + + if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) { + + ScriptServer::edit_request_func(base_script); //make sure it's loaded + } + + if (ResourceCache::has(base_script)) { + + script = Ref<Resource>( ResourceCache::get(base_script) ); + } else { + return; + } + } + } + + List<PropertyInfo> pinfo; + + + if (node) { + + node->get_property_list(&pinfo); + } else { + ObjectTypeDB::get_property_list(type,&pinfo); + } + + if (script.is_valid()) { + + script->get_script_property_list(&pinfo); + } + + for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { + + if (E->get().name==property) { + type_cache=E->get(); + return; + } + } + + } +} + void VisualScriptPropertySet::set_property(const StringName& p_type){ if (property==p_type) return; property=p_type; + _update_cache(); _change_notify(); ports_changed_notify(); } @@ -896,34 +1353,17 @@ VisualScriptPropertySet::CallMode VisualScriptPropertySet::get_call_mode() const } -void VisualScriptPropertySet::set_use_builtin_value(bool p_use) { - if (use_builtin_value==p_use) - return; - - use_builtin_value=p_use; - _change_notify(); - ports_changed_notify(); +void VisualScriptPropertySet::_set_type_cache(const Dictionary &p_type) { + type_cache=PropertyInfo::from_dict(p_type); } -bool VisualScriptPropertySet::is_using_builtin_value() const{ +Dictionary VisualScriptPropertySet::_get_type_cache() const { - return use_builtin_value; + return type_cache; } -void VisualScriptPropertySet::set_builtin_value(const Variant& p_value){ - - if (builtin_value==p_value) - return; - - builtin_value=p_value; - -} -Variant VisualScriptPropertySet::get_builtin_value() const{ - - return builtin_value; -} void VisualScriptPropertySet::_validate_property(PropertyInfo& property) const { if (property.name=="property/base_type") { @@ -932,6 +1372,11 @@ void VisualScriptPropertySet::_validate_property(PropertyInfo& property) const { } } + if (property.name=="property/base_script") { + if (call_mode!=CALL_MODE_INSTANCE) { + property.usage=0; + } + } if (property.name=="property/basic_type") { if (call_mode!=CALL_MODE_BASIC_TYPE) { @@ -972,6 +1417,24 @@ void VisualScriptPropertySet::_validate_property(PropertyInfo& property) const { } else if (call_mode==CALL_MODE_INSTANCE) { property.hint=PROPERTY_HINT_PROPERTY_OF_BASE_TYPE; property.hint_string=base_type; + + if (base_script!=String()) { + if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) { + + ScriptServer::edit_request_func(base_script); //make sure it's loaded + } + + if (ResourceCache::has(base_script)) { + + Ref<Script> script = Ref<Resource>( ResourceCache::get(base_script) ); + if (script.is_valid()) { + + property.hint=PROPERTY_HINT_PROPERTY_OF_SCRIPT; + property.hint_string=itos(script->get_instance_ID()); + } + } + } + } else if (call_mode==CALL_MODE_NODE_PATH) { Node *node = _get_base_node(); if (node) { @@ -986,42 +1449,6 @@ void VisualScriptPropertySet::_validate_property(PropertyInfo& property) const { } - if (property.name=="value/builtin") { - - if (!use_builtin_value) { - property.usage=0; - } else { - List<PropertyInfo> pinfo; - - if (call_mode==CALL_MODE_BASIC_TYPE) { - Variant::CallError ce; - Variant 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(); - if (n) { - n->get_property_list(&pinfo); - } else { - ObjectTypeDB::get_property_list(_get_base_type(),&pinfo); - } - } else { - ObjectTypeDB::get_property_list(_get_base_type(),&pinfo); - } - - for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { - - if (E->get().name==this->property) { - - property.hint=E->get().hint; - property.type=E->get().type; - property.hint_string=E->get().hint_string; - } - } - } - - } } void VisualScriptPropertySet::_bind_methods() { @@ -1029,10 +1456,15 @@ void VisualScriptPropertySet::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_base_type","base_type"),&VisualScriptPropertySet::set_base_type); ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptPropertySet::get_base_type); + ObjectTypeDB::bind_method(_MD("set_base_script","base_script"),&VisualScriptPropertySet::set_base_script); + ObjectTypeDB::bind_method(_MD("get_base_script"),&VisualScriptPropertySet::get_base_script); 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_type_cache","type_cache"),&VisualScriptPropertySet::_set_type_cache); + ObjectTypeDB::bind_method(_MD("_get_type_cache"),&VisualScriptPropertySet::_get_type_cache); + ObjectTypeDB::bind_method(_MD("set_event_type","event_type"),&VisualScriptPropertySet::set_event_type); ObjectTypeDB::bind_method(_MD("get_event_type"),&VisualScriptPropertySet::get_event_type); @@ -1045,11 +1477,7 @@ void VisualScriptPropertySet::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_base_path","base_path"),&VisualScriptPropertySet::set_base_path); ObjectTypeDB::bind_method(_MD("get_base_path"),&VisualScriptPropertySet::get_base_path); - ObjectTypeDB::bind_method(_MD("set_builtin_value","value"),&VisualScriptPropertySet::set_builtin_value); - ObjectTypeDB::bind_method(_MD("get_builtin_value"),&VisualScriptPropertySet::get_builtin_value); - ObjectTypeDB::bind_method(_MD("set_use_builtin_value","enable"),&VisualScriptPropertySet::set_use_builtin_value); - ObjectTypeDB::bind_method(_MD("is_using_builtin_value"),&VisualScriptPropertySet::is_using_builtin_value); String bt; for(int i=0;i<Variant::VARIANT_MAX;i++) { @@ -1067,15 +1495,26 @@ void VisualScriptPropertySet::_bind_methods() { et+=event_type_names[i]; } + List<String> script_extensions; + for(int i=0;i<ScriptServer::get_language_count();i++) { + ScriptServer::get_language(i)->get_recognized_extensions(&script_extensions); + } + + String script_ext_hint; + for (List<String>::Element *E=script_extensions.front();E;E=E->next()) { + if (script_ext_hint!=String()) + script_ext_hint+=","; + script_ext_hint+="*."+E->get(); + } ADD_PROPERTY(PropertyInfo(Variant::INT,"property/set_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance,Basic Type"),_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::STRING,"property/base_script",PROPERTY_HINT_FILE,script_ext_hint),_SCS("set_base_script"),_SCS("get_base_script")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"property/type_cache",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_type_cache"),_SCS("_get_type_cache")); 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")); - ADD_PROPERTY(PropertyInfo(Variant::NIL,"value/builtin"),_SCS("set_builtin_value"),_SCS("get_builtin_value")); BIND_CONSTANT( CALL_MODE_SELF ); BIND_CONSTANT( CALL_MODE_NODE_PATH); @@ -1090,8 +1529,6 @@ public: VisualScriptPropertySet::CallMode call_mode; NodePath node_path; StringName property; - bool use_builtin; - Variant builtin_val; VisualScriptPropertySet *node; VisualScriptInstance *instance; @@ -1113,15 +1550,11 @@ public: bool valid; - if (use_builtin) { - object->set(property,builtin_val,&valid); - } else { - object->set(property,*p_inputs[0],&valid); - } + 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."; + r_error_str="Invalid set value '"+String(*p_inputs[0])+"' on property '"+String(property)+"' of type "+object->get_type(); } } break; case VisualScriptPropertySet::CALL_MODE_NODE_PATH: { @@ -1142,15 +1575,11 @@ public: bool valid; - if (use_builtin) { - another->set(property,builtin_val,&valid); - } else { - another->set(property,*p_inputs[0],&valid); - } + 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."; + r_error_str="Invalid set value '"+String(*p_inputs[0])+"' on property '"+String(property)+"' of type "+another->get_type(); } } break; @@ -1161,20 +1590,14 @@ public: bool valid; - if (use_builtin) { - v.set(property,builtin_val,&valid); - } else { - v.set(property,p_inputs[1],&valid); - } + 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."; + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Invalid set value '"+String(*p_inputs[1])+"' ("+Variant::get_type_name(p_inputs[1]->get_type())+") on property '"+String(property)+"' of type "+Variant::get_type_name(v.get_type()); } - if (call_mode==VisualScriptPropertySet::CALL_MODE_BASIC_TYPE) { - *p_outputs[0]=v; - } + *p_outputs[0]=v; } break; @@ -1194,11 +1617,20 @@ VisualScriptNodeInstance* VisualScriptPropertySet::instance(VisualScriptInstance 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::TypeGuess VisualScriptPropertySet::guess_output_type(TypeGuess* p_inputs, int p_output) const { + + if (p_output==0 && call_mode==CALL_MODE_INSTANCE) { + return p_inputs[0]; + } + + return VisualScriptNode::guess_output_type(p_inputs,p_output); + +} VisualScriptPropertySet::VisualScriptPropertySet() { call_mode=CALL_MODE_SELF; @@ -1224,12 +1656,12 @@ static Ref<VisualScriptNode> create_property_set_node(const String& p_name) { int VisualScriptPropertyGet::get_output_sequence_port_count() const { - return (call_mode==CALL_MODE_SELF || call_mode==CALL_MODE_NODE_PATH)?0:1; + return 0;// (call_mode==CALL_MODE_SELF || call_mode==CALL_MODE_NODE_PATH)?0:1; } bool VisualScriptPropertyGet::has_input_sequence_port() const{ - return (call_mode==CALL_MODE_SELF || call_mode==CALL_MODE_NODE_PATH)?false:true; + return false;//(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 @@ -1299,6 +1731,7 @@ StringName VisualScriptPropertyGet::_get_base_type() const { return base_type; } + int VisualScriptPropertyGet::get_input_value_port_count() const{ return (call_mode==CALL_MODE_BASIC_TYPE || call_mode==CALL_MODE_INSTANCE)?1:0; @@ -1332,17 +1765,75 @@ PropertyInfo VisualScriptPropertyGet::get_input_value_port_info(int p_idx) const PropertyInfo VisualScriptPropertyGet::get_output_value_port_info(int p_idx) const{ + return PropertyInfo(type_cache,"value"); +} -#ifdef DEBUG_METHODS_ENABLED +String VisualScriptPropertyGet::get_caption() const { - //not very efficient but.. + static const char*cname[4]= { + "SelfGet", + "NodeGet", + "InstanceGet", + "BasicGet" + }; + + return cname[call_mode]; +} + +String VisualScriptPropertyGet::get_text() const { + + String prop; + + if (call_mode==CALL_MODE_BASIC_TYPE) + prop=Variant::get_type_name(basic_type)+"."+property; + else if (call_mode==CALL_MODE_NODE_PATH) + prop=String(base_path)+":"+property; + else if (call_mode==CALL_MODE_SELF) + prop=property; + else if (call_mode==CALL_MODE_INSTANCE) + prop=String(base_type)+":"+property; + + return prop; +} + +void VisualScriptPropertyGet::set_base_type(const StringName& p_type) { + + if (base_type==p_type) + return; + + base_type=p_type; + _change_notify(); + ports_changed_notify(); +} + +StringName VisualScriptPropertyGet::get_base_type() const{ + + return base_type; +} + +void VisualScriptPropertyGet::set_base_script(const String& p_path) { + + if (base_script==p_path) + return; + + base_script=p_path; + _change_notify(); + ports_changed_notify(); +} +String VisualScriptPropertyGet::get_base_script() const { + + return base_script; +} + + +void VisualScriptPropertyGet::_update_cache() { - List<PropertyInfo> pinfo; if (call_mode==CALL_MODE_BASIC_TYPE) { + //not super efficient.. Variant v; if (basic_type==Variant::INPUT_EVENT) { @@ -1353,71 +1844,91 @@ PropertyInfo VisualScriptPropertyGet::get_output_value_port_info(int p_idx) cons Variant::CallError ce; v = Variant::construct(basic_type,NULL,0,ce); } + + List<PropertyInfo> pinfo; v.get_property_list(&pinfo); - } else if (call_mode==CALL_MODE_NODE_PATH) { - Node *n = _get_base_node(); - if (n) { - n->get_property_list(&pinfo); - } else { - ObjectTypeDB::get_property_list(_get_base_type(),&pinfo); + for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { + + if (E->get().name==property) { + + type_cache=E->get().type; + return; + } } + } else { - ObjectTypeDB::get_property_list(_get_base_type(),&pinfo); - } - for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { - if (E->get().name==property) { + StringName type; + Ref<Script> script; + Node *node=NULL; - PropertyInfo info=E->get(); - info.name=""; - return info; - } - } + if (call_mode==CALL_MODE_NODE_PATH) { + node=_get_base_node(); + if (node) { + type=node->get_type(); + base_type=type; //cache, too + script = node->get_script(); + } + } else if (call_mode==CALL_MODE_SELF) { -#endif + if (get_visual_script().is_valid()) { + type=get_visual_script()->get_instance_base_type(); + base_type=type; //cache, too + script=get_visual_script(); + } + } else if (call_mode==CALL_MODE_INSTANCE) { - return PropertyInfo(Variant::NIL,""); -} + type=base_type; + if (base_script!=String()) { + if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) { -String VisualScriptPropertyGet::get_caption() const { + ScriptServer::edit_request_func(base_script); //make sure it's loaded + } - static const char*cname[4]= { - "SelfGet", - "NodeGet", - "InstanceGet", - "BasicGet" - }; + if (ResourceCache::has(base_script)) { - return cname[call_mode]; -} + script = Ref<Resource>( ResourceCache::get(base_script) ); + } else { + return; + } + } + } -String VisualScriptPropertyGet::get_text() const { + bool valid=false; - if (call_mode==CALL_MODE_BASIC_TYPE) - return Variant::get_type_name(basic_type)+"."+property; - else - return property; + Variant::Type type_ret; -} + type_ret=ObjectTypeDB::get_property_type(base_type,property,&valid); -void VisualScriptPropertyGet::set_base_type(const StringName& p_type) { + if (valid) { + type_cache=type_ret; + return; //all dandy + } - if (base_type==p_type) - return; + if (node) { - base_type=p_type; - _change_notify(); - ports_changed_notify(); -} + Variant prop = node->get(property,&valid); + if (valid) { + type_cache=prop.get_type(); + return; //all dandy again + } + } -StringName VisualScriptPropertyGet::get_base_type() const{ + if (script.is_valid()) { - return base_type; + type_ret=script->get_static_property_type(property,&valid); + + if (valid) { + type_cache=type_ret; + return; //all dandy + } + } + } } void VisualScriptPropertyGet::set_property(const StringName& p_type){ @@ -1426,6 +1937,9 @@ void VisualScriptPropertyGet::set_property(const StringName& p_type){ return; property=p_type; + + + _update_cache(); _change_notify(); ports_changed_notify(); } @@ -1492,6 +2006,9 @@ void VisualScriptPropertyGet::set_event_type(InputEvent::Type p_type) { if (event_type==p_type) return; event_type=p_type; + if(call_mode==CALL_MODE_BASIC_TYPE) { + _update_cache(); + } _change_notify(); _update_base_type(); ports_changed_notify(); @@ -1502,6 +2019,17 @@ InputEvent::Type VisualScriptPropertyGet::get_event_type() const{ return event_type; } + +void VisualScriptPropertyGet::_set_type_cache(Variant::Type p_type) { + type_cache=p_type; +} + +Variant::Type VisualScriptPropertyGet::_get_type_cache() const { + + return type_cache; +} + + void VisualScriptPropertyGet::_validate_property(PropertyInfo& property) const { if (property.name=="property/base_type") { @@ -1510,6 +2038,11 @@ void VisualScriptPropertyGet::_validate_property(PropertyInfo& property) const { } } + if (property.name=="property/base_script") { + if (call_mode!=CALL_MODE_INSTANCE) { + property.usage=0; + } + } if (property.name=="property/basic_type") { if (call_mode!=CALL_MODE_BASIC_TYPE) { @@ -1549,6 +2082,23 @@ void VisualScriptPropertyGet::_validate_property(PropertyInfo& property) const { } else if (call_mode==CALL_MODE_INSTANCE) { property.hint=PROPERTY_HINT_PROPERTY_OF_BASE_TYPE; property.hint_string=base_type; + + if (base_script!=String()) { + if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) { + + ScriptServer::edit_request_func(base_script); //make sure it's loaded + } + + if (ResourceCache::has(base_script)) { + + Ref<Script> script = Ref<Resource>( ResourceCache::get(base_script) ); + if (script.is_valid()) { + + property.hint=PROPERTY_HINT_PROPERTY_OF_SCRIPT; + property.hint_string=itos(script->get_instance_ID()); + } + } + } } else if (call_mode==CALL_MODE_NODE_PATH) { Node *node = _get_base_node(); if (node) { @@ -1570,10 +2120,15 @@ void VisualScriptPropertyGet::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_base_type","base_type"),&VisualScriptPropertyGet::set_base_type); ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptPropertyGet::get_base_type); + ObjectTypeDB::bind_method(_MD("set_base_script","base_script"),&VisualScriptPropertyGet::set_base_script); + ObjectTypeDB::bind_method(_MD("get_base_script"),&VisualScriptPropertyGet::get_base_script); 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_type_cache","type_cache"),&VisualScriptPropertyGet::_set_type_cache); + ObjectTypeDB::bind_method(_MD("_get_type_cache"),&VisualScriptPropertyGet::_get_type_cache); + ObjectTypeDB::bind_method(_MD("set_event_type","event_type"),&VisualScriptPropertyGet::set_event_type); ObjectTypeDB::bind_method(_MD("get_event_type"),&VisualScriptPropertyGet::get_event_type); @@ -1603,9 +2158,22 @@ void VisualScriptPropertyGet::_bind_methods() { et+=event_type_names[i]; } + List<String> script_extensions; + for(int i=0;i<ScriptServer::get_language_count();i++) { + ScriptServer::get_language(i)->get_recognized_extensions(&script_extensions); + } + + String script_ext_hint; + for (List<String>::Element *E=script_extensions.front();E;E=E->next()) { + if (script_ext_hint!=String()) + script_ext_hint+=","; + script_ext_hint+="."+E->get(); + } - ADD_PROPERTY(PropertyInfo(Variant::INT,"property/set_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance"),_SCS("set_call_mode"),_SCS("get_call_mode")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"property/set_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance,Basic Type"),_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::STRING,"property/base_script",PROPERTY_HINT_FILE,script_ext_hint),_SCS("set_base_script"),_SCS("get_base_script")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"property/type_cache",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_type_cache"),_SCS("_get_type_cache")); 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")); @@ -1628,12 +2196,10 @@ public: VisualScriptInstance *instance; + 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) { + - //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: { @@ -1642,63 +2208,57 @@ public: bool valid; - *r_value = object->get(property,&valid); + *p_outputs[0] = object->get(property,&valid); if (!valid) { - //r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; - r_error=RTR("Invalid index property name."); - return false; + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str=RTR("Invalid index property name."); + return 0; } } 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; + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str=RTR("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=RTR("Path does not lead Node!"); - return false; + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str=RTR("Path does not lead Node!"); + return 0; } bool valid; - *r_value = another->get(property,&valid); + *p_outputs[0] = 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; + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str=vformat(RTR("Invalid index property name '%s' in node %s."),String(property),another->get_name()); + return 0; } } break; - default: {}; - } - return true; - - } + default: { - 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]; + bool valid; + Variant v = *p_inputs[0]; - *p_outputs[0] = v.get(property,&valid); + *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."); + if (!valid) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str=RTR("Invalid index property name."); + } + }; } - return 0; } @@ -1725,6 +2285,7 @@ VisualScriptPropertyGet::VisualScriptPropertyGet() { base_type="Object"; basic_type=Variant::NIL; event_type=InputEvent::NONE; + type_cache=Variant::NIL; } diff --git a/modules/visual_script/visual_script_func_nodes.h b/modules/visual_script/visual_script_func_nodes.h index 7bb5ec49a2..43ef276cf4 100644 --- a/modules/visual_script/visual_script_func_nodes.h +++ b/modules/visual_script/visual_script_func_nodes.h @@ -13,20 +13,40 @@ public: CALL_MODE_NODE_PATH, CALL_MODE_INSTANCE, CALL_MODE_BASIC_TYPE, + CALL_MODE_SINGLETON, }; + + enum RPCCallMode { + RPC_DISABLED, + RPC_RELIABLE, + RPC_UNRELIABLE, + RPC_RELIABLE_TO_ID, + RPC_UNRELIABLE_TO_ID + }; + private: CallMode call_mode; StringName base_type; + String base_script; Variant::Type basic_type; NodePath base_path; StringName function; int use_default_args; + RPCCallMode rpc_call_mode; + StringName singleton; + bool validate; + Node *_get_base_node() const; StringName _get_base_type() const; - void _update_defargs(); + MethodInfo method_cache; + void _update_method_cache(); + + void _set_argument_cache(const Dictionary& p_args); + Dictionary _get_argument_cache() const; + protected: virtual void _validate_property(PropertyInfo& property) const; @@ -58,24 +78,41 @@ public: void set_base_type(const StringName& p_type); StringName get_base_type() const; + void set_base_script(const String& p_path); + String get_base_script() const; + + void set_singleton(const StringName& p_type); + StringName get_singleton() const; + void set_function(const StringName& p_type); StringName get_function() const; void set_base_path(const NodePath& p_type); NodePath get_base_path() const; + void set_call_mode(CallMode p_mode); CallMode get_call_mode() const; void set_use_default_args(int p_amount); int get_use_default_args() const; + void set_validate(bool p_amount); + bool get_validate() const; + + void set_rpc_call_mode(RPCCallMode p_mode); + RPCCallMode get_rpc_call_mode() const; + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + virtual TypeGuess guess_output_type(TypeGuess* p_inputs, int p_output) const; + + VisualScriptFunctionCall(); }; VARIANT_ENUM_CAST(VisualScriptFunctionCall::CallMode ); +VARIANT_ENUM_CAST(VisualScriptFunctionCall::RPCCallMode ); class VisualScriptPropertySet : public VisualScriptNode { @@ -92,13 +129,14 @@ public: }; private: + PropertyInfo type_cache; + CallMode call_mode; Variant::Type basic_type; StringName base_type; + String base_script; NodePath base_path; StringName property; - bool use_builtin_value; - Variant builtin_value; InputEvent::Type event_type; Node *_get_base_node() const; @@ -106,6 +144,12 @@ private: void _update_base_type(); + void _update_cache(); + + void _set_type_cache(const Dictionary& p_type); + Dictionary _get_type_cache() const; + + protected: virtual void _validate_property(PropertyInfo& property) const; @@ -134,6 +178,9 @@ public: void set_base_type(const StringName& p_type); StringName get_base_type() const; + void set_base_script(const String& p_path); + String get_base_script() const; + void set_basic_type(Variant::Type p_type); Variant::Type get_basic_type() const; @@ -149,13 +196,9 @@ public: void set_call_mode(CallMode p_mode); CallMode get_call_mode() const; - void set_use_builtin_value(bool p_use); - bool is_using_builtin_value() const; - - void set_builtin_value(const Variant &p_value); - Variant get_builtin_value() const; virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + virtual TypeGuess guess_output_type(TypeGuess* p_inputs, int p_output) const; VisualScriptPropertySet(); }; @@ -171,14 +214,17 @@ public: CALL_MODE_SELF, CALL_MODE_NODE_PATH, CALL_MODE_INSTANCE, - CALL_MODE_BASIC_TYPE + CALL_MODE_BASIC_TYPE, }; private: + Variant::Type type_cache; + CallMode call_mode; Variant::Type basic_type; StringName base_type; + String base_script; NodePath base_path; StringName property; InputEvent::Type event_type; @@ -187,6 +233,10 @@ private: Node *_get_base_node() const; StringName _get_base_type() const; + void _update_cache(); + + void _set_type_cache(Variant::Type p_type); + Variant::Type _get_type_cache() const; protected: virtual void _validate_property(PropertyInfo& property) const; @@ -216,6 +266,9 @@ public: void set_base_type(const StringName& p_type); StringName get_base_type() const; + void set_base_script(const String& p_path); + String get_base_script() const; + void set_basic_type(Variant::Type p_type); Variant::Type get_basic_type() const; @@ -283,6 +336,9 @@ public: 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 d205a40f76..7ada292b13 100644 --- a/modules/visual_script/visual_script_nodes.cpp +++ b/modules/visual_script/visual_script_nodes.cpp @@ -4,6 +4,7 @@ #include "scene/main/scene_main_loop.h" #include "os/os.h" #include "scene/main/node.h" +#include "os/input.h" ////////////////////////////////////////// ////////////////FUNCTION////////////////// @@ -62,6 +63,12 @@ bool VisualScriptFunction::_set(const StringName& p_name, const Variant& p_valu stack_size=p_value; return true; } + + if (p_name=="rpc/mode") { + rpc_mode=ScriptInstance::RPCMode(int(p_value)); + return true; + } + return false; } @@ -99,13 +106,18 @@ bool VisualScriptFunction::_get(const StringName& p_name,Variant &r_ret) const return true; } + if (p_name=="rpc/mode") { + r_ret=rpc_mode; + return true; + } + return false; } void VisualScriptFunction::_get_property_list( List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::INT,"argument_count",PROPERTY_HINT_RANGE,"0,256")); - String argt="Variant"; + String argt="Any"; for(int i=1;i<Variant::VARIANT_MAX;i++) { argt+=","+Variant::get_type_name(Variant::Type(i)); } @@ -118,6 +130,7 @@ void VisualScriptFunction::_get_property_list( List<PropertyInfo> *p_list) cons p_list->push_back(PropertyInfo(Variant::INT,"stack/size",PROPERTY_HINT_RANGE,"1,100000")); } p_list->push_back(PropertyInfo(Variant::BOOL,"stack/stackless")); + p_list->push_back(PropertyInfo(Variant::INT,"rpc/mode",PROPERTY_HINT_ENUM,"Disabled,Remote,Sync,Master,Slave")); } @@ -224,6 +237,16 @@ int VisualScriptFunction::get_argument_count() const { return arguments.size(); } + +void VisualScriptFunction::set_rpc_mode(ScriptInstance::RPCMode p_mode) { + rpc_mode=p_mode; +} + +ScriptInstance::RPCMode VisualScriptFunction::get_rpc_mode() const { + return rpc_mode; +} + + class VisualScriptNodeInstanceFunction : public VisualScriptNodeInstance { public: @@ -231,8 +254,6 @@ public: VisualScriptInstance *instance; //virtual int get_working_memory_size() const { return 0; } - //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } - //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return 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) { @@ -272,6 +293,7 @@ VisualScriptFunction::VisualScriptFunction() { stack_size=256; stack_less=false; + rpc_mode=ScriptInstance::RPC_MODE_DISABLED; } @@ -302,12 +324,12 @@ int VisualScriptFunction::get_stack_size() const { int VisualScriptOperator::get_output_sequence_port_count() const { - return 1; + return 0; } bool VisualScriptOperator::has_input_sequence_port() const{ - return true; + return false; } int VisualScriptOperator::get_input_value_port_count() const{ @@ -362,6 +384,8 @@ PropertyInfo VisualScriptOperator::get_input_value_port_info(int p_idx) const{ PropertyInfo pinfo; pinfo.name=p_idx==0?"A":"B"; pinfo.type=port_types[op][p_idx]; + if (pinfo.type==Variant::NIL) + pinfo.type=typed; return pinfo; } PropertyInfo VisualScriptOperator::get_output_value_port_info(int p_idx) const{ @@ -400,6 +424,8 @@ PropertyInfo VisualScriptOperator::get_output_value_port_info(int p_idx) const{ PropertyInfo pinfo; pinfo.name=""; pinfo.type=port_types[op]; + if (pinfo.type==Variant::NIL) + pinfo.type=typed; return pinfo; } @@ -492,19 +518,43 @@ Variant::Operator VisualScriptOperator::get_operator() const{ return op; } +void VisualScriptOperator::set_typed(Variant::Type p_op) { + + if (typed==p_op) + return; + + typed=p_op; + ports_changed_notify(); +} + +Variant::Type VisualScriptOperator::get_typed() const { + + return typed; +} + void VisualScriptOperator::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_operator","op"),&VisualScriptOperator::set_operator); ObjectTypeDB::bind_method(_MD("get_operator"),&VisualScriptOperator::get_operator); + ObjectTypeDB::bind_method(_MD("set_typed","type"),&VisualScriptOperator::set_typed); + ObjectTypeDB::bind_method(_MD("get_typed"),&VisualScriptOperator::get_typed); + String types; for(int i=0;i<Variant::OP_MAX;i++) { if (i>0) types+=","; types+=op_names[i]; } + + String argt="Any"; + for(int i=1;i<Variant::VARIANT_MAX;i++) { + argt+=","+Variant::get_type_name(Variant::Type(i)); + } + ADD_PROPERTY(PropertyInfo(Variant::INT,"operator_value/type",PROPERTY_HINT_ENUM,types),_SCS("set_operator"),_SCS("get_operator")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"typed_value/typed",PROPERTY_HINT_ENUM,argt),_SCS("set_typed"),_SCS("get_typed")); } @@ -515,8 +565,6 @@ public: 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) { @@ -558,6 +606,7 @@ VisualScriptNodeInstance* VisualScriptOperator::instance(VisualScriptInstance* p VisualScriptOperator::VisualScriptOperator() { op=Variant::OP_ADD; + typed=Variant::NIL; } @@ -679,20 +728,14 @@ public: 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) { + if (instance->get_variable(variable,p_outputs[0])==false) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str=RTR("VariableGet not found in script: ")+"'"+String(variable)+"'"; + return false; + } return 0; } @@ -714,7 +757,7 @@ VisualScriptVariableGet::VisualScriptVariableGet() { ////////////////////////////////////////// -////////////////VARIABLE GET////////////////// +////////////////VARIABLE SET////////////////// ////////////////////////////////////////// int VisualScriptVariableSet::get_output_sequence_port_count() const { @@ -822,17 +865,16 @@ public: 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.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; r_error_str=RTR("VariableSet not found in script: ")+"'"+String(variable)+"'"; } - return 0; } @@ -971,17 +1013,10 @@ public: 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) { + *p_outputs[0]=constant; return 0; } @@ -1001,6 +1036,124 @@ VisualScriptConstant::VisualScriptConstant() { } +////////////////////////////////////////// +////////////////PRELOAD////////////////// +////////////////////////////////////////// + +int VisualScriptPreload::get_output_sequence_port_count() const { + + return 0; +} + +bool VisualScriptPreload::has_input_sequence_port() const{ + + return false; +} + +int VisualScriptPreload::get_input_value_port_count() const{ + + return 0; +} +int VisualScriptPreload::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptPreload::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptPreload::get_input_value_port_info(int p_idx) const{ + + return PropertyInfo(); +} + +PropertyInfo VisualScriptPreload::get_output_value_port_info(int p_idx) const{ + + PropertyInfo pinfo=PropertyInfo(Variant::OBJECT,"res"); + if (preload.is_valid()) { + pinfo.hint=PROPERTY_HINT_RESOURCE_TYPE; + pinfo.hint_string=preload->get_type(); + } + + return pinfo; +} + + +String VisualScriptPreload::get_caption() const { + + return "Preload"; +} + +String VisualScriptPreload::get_text() const { + + if (preload.is_valid()) { + if (preload->get_path().is_resource_file()) { + return preload->get_path(); + } else if (preload->get_name()!=String()) { + return preload->get_name(); + } else { + return preload->get_type(); + } + } else { + return "<empty>"; + } +} + + +void VisualScriptPreload::set_preload(const Ref<Resource>& p_preload){ + + if (preload==p_preload) + return; + + preload=p_preload; + ports_changed_notify(); +} +Ref<Resource> VisualScriptPreload::get_preload() const{ + + return preload; +} + + +void VisualScriptPreload::_bind_methods() { + + + ObjectTypeDB::bind_method(_MD("set_preload","resource"),&VisualScriptPreload::set_preload); + ObjectTypeDB::bind_method(_MD("get_preload"),&VisualScriptPreload::get_preload); + + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"resource",PROPERTY_HINT_RESOURCE_TYPE,"Resource"),_SCS("set_preload"),_SCS("get_preload")); + +} + +class VisualScriptNodeInstancePreload : public VisualScriptNodeInstance { +public: + + Ref<Resource> preload; + //virtual int get_working_memory_size() const { return 0; } + + 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) { + + *p_outputs[0]=preload; + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptPreload::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstancePreload * instance = memnew(VisualScriptNodeInstancePreload ); + instance->preload=preload; + return instance; +} + +VisualScriptPreload::VisualScriptPreload() { + +} + + ////////////////////////////////////////// @@ -1009,12 +1162,12 @@ VisualScriptConstant::VisualScriptConstant() { int VisualScriptIndexGet::get_output_sequence_port_count() const { - return 1; + return 0; } bool VisualScriptIndexGet::has_input_sequence_port() const{ - return true; + return false; } int VisualScriptIndexGet::get_input_value_port_count() const{ @@ -1063,8 +1216,6 @@ public: //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) { @@ -1155,8 +1306,6 @@ public: //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) { @@ -1252,17 +1401,11 @@ public: 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 { - - *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) { + *p_outputs[0] = GlobalConstants::get_global_constant_value(index); return 0; } @@ -1297,6 +1440,286 @@ VisualScriptGlobalConstant::VisualScriptGlobalConstant() { index=0; } +////////////////////////////////////////// +////////////////CLASSCONSTANT/////////// +////////////////////////////////////////// + +int VisualScriptClassConstant::get_output_sequence_port_count() const { + + return 0; +} + +bool VisualScriptClassConstant::has_input_sequence_port() const{ + + return false; +} + +int VisualScriptClassConstant::get_input_value_port_count() const{ + + return 0; +} +int VisualScriptClassConstant::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptClassConstant::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptClassConstant::get_input_value_port_info(int p_idx) const{ + + return PropertyInfo(); +} + +PropertyInfo VisualScriptClassConstant::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(Variant::INT,"value"); +} + + +String VisualScriptClassConstant::get_caption() const { + + return "ClassConst"; +} + +String VisualScriptClassConstant::get_text() const { + + return String(base_type)+"."+String(name); +} + +void VisualScriptClassConstant::set_class_constant(const StringName& p_which) { + + name=p_which; + _change_notify(); + ports_changed_notify(); +} + +StringName VisualScriptClassConstant::get_class_constant() { + return name; +} + + +void VisualScriptClassConstant::set_base_type(const StringName& p_which) { + + base_type=p_which; + _change_notify(); + ports_changed_notify(); +} + +StringName VisualScriptClassConstant::get_base_type() { + return base_type; +} + +class VisualScriptNodeInstanceClassConstant : public VisualScriptNodeInstance { +public: + + int value; + bool valid; + //virtual int get_working_memory_size() const { return 0; } + + 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="Invalid constant name, pick a valid class constant."; + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + } + + *p_outputs[0] = value; + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptClassConstant::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceClassConstant * instance = memnew(VisualScriptNodeInstanceClassConstant ); + instance->value=ObjectTypeDB::get_integer_constant(base_type,name,&instance->valid); + return instance; +} + +void VisualScriptClassConstant::_validate_property(PropertyInfo& property) const { + + if (property.name=="constant") { + + List<String> constants; + ObjectTypeDB::get_integer_constant_list(base_type,&constants,true); + + property.hint_string=""; + for(List<String>::Element *E=constants.front();E;E=E->next()) { + if (property.hint_string!=String()) { + property.hint_string+=","; + } + property.hint_string+=E->get(); + } + } +} + +void VisualScriptClassConstant::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_class_constant","name"),&VisualScriptClassConstant::set_class_constant); + ObjectTypeDB::bind_method(_MD("get_class_constant"),&VisualScriptClassConstant::get_class_constant); + + ObjectTypeDB::bind_method(_MD("set_base_type","name"),&VisualScriptClassConstant::set_base_type); + ObjectTypeDB::bind_method(_MD("get_base_type"),&VisualScriptClassConstant::get_base_type); + + ADD_PROPERTY(PropertyInfo(Variant::STRING,"base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type")); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"constant",PROPERTY_HINT_ENUM,""),_SCS("set_class_constant"),_SCS("get_class_constant")); +} + +VisualScriptClassConstant::VisualScriptClassConstant() { + + base_type="Object"; +} + + +////////////////////////////////////////// +////////////////BASICTYPECONSTANT/////////// +////////////////////////////////////////// + +int VisualScriptBasicTypeConstant::get_output_sequence_port_count() const { + + return 0; +} + +bool VisualScriptBasicTypeConstant::has_input_sequence_port() const{ + + return false; +} + +int VisualScriptBasicTypeConstant::get_input_value_port_count() const{ + + return 0; +} +int VisualScriptBasicTypeConstant::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptBasicTypeConstant::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptBasicTypeConstant::get_input_value_port_info(int p_idx) const{ + + return PropertyInfo(); +} + +PropertyInfo VisualScriptBasicTypeConstant::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(Variant::INT,"value"); +} + + +String VisualScriptBasicTypeConstant::get_caption() const { + + return "BasicConst"; +} + +String VisualScriptBasicTypeConstant::get_text() const { + + return Variant::get_type_name(type)+"."+String(name); +} + +void VisualScriptBasicTypeConstant::set_basic_type_constant(const StringName& p_which) { + + name=p_which; + _change_notify(); + ports_changed_notify(); +} + +StringName VisualScriptBasicTypeConstant::get_basic_type_constant() const { + return name; +} + + +void VisualScriptBasicTypeConstant::set_basic_type(Variant::Type p_which) { + + type=p_which; + _change_notify(); + ports_changed_notify(); +} + +Variant::Type VisualScriptBasicTypeConstant::get_basic_type() const { + return type; +} + +class VisualScriptNodeInstanceBasicTypeConstant : public VisualScriptNodeInstance { +public: + + int value; + bool valid; + //virtual int get_working_memory_size() const { return 0; } + + 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="Invalid constant name, pick a valid basic type constant."; + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + } + + *p_outputs[0] = value; + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptBasicTypeConstant::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceBasicTypeConstant * instance = memnew(VisualScriptNodeInstanceBasicTypeConstant ); + instance->value=Variant::get_numeric_constant_value(type,name,&instance->valid); + return instance; +} + +void VisualScriptBasicTypeConstant::_validate_property(PropertyInfo& property) const { + + if (property.name=="constant") { + + List<StringName> constants; + Variant::get_numeric_constants_for_type(type,&constants); + + if (constants.size()==0) { + property.usage=0; + return; + } + property.hint_string=""; + for(List<StringName>::Element *E=constants.front();E;E=E->next()) { + if (property.hint_string!=String()) { + property.hint_string+=","; + } + property.hint_string+=String(E->get()); + } + + } +} + +void VisualScriptBasicTypeConstant::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_basic_type","name"),&VisualScriptBasicTypeConstant::set_basic_type); + ObjectTypeDB::bind_method(_MD("get_basic_type"),&VisualScriptBasicTypeConstant::get_basic_type); + + ObjectTypeDB::bind_method(_MD("set_basic_type_constant","name"),&VisualScriptBasicTypeConstant::set_basic_type_constant); + ObjectTypeDB::bind_method(_MD("get_basic_type_constant"),&VisualScriptBasicTypeConstant::get_basic_type_constant); + + + String argt="Null"; + for(int i=1;i<Variant::VARIANT_MAX;i++) { + argt+=","+Variant::get_type_name(Variant::Type(i)); + } + + ADD_PROPERTY(PropertyInfo(Variant::INT,"basic_type",PROPERTY_HINT_ENUM,argt),_SCS("set_basic_type"),_SCS("get_basic_type")); + ADD_PROPERTY(PropertyInfo(Variant::STRING,"constant",PROPERTY_HINT_ENUM,""),_SCS("set_basic_type_constant"),_SCS("get_basic_type_constant")); +} + +VisualScriptBasicTypeConstant::VisualScriptBasicTypeConstant() { + + type=Variant::NIL; +} + ////////////////////////////////////////// @@ -1384,17 +1807,10 @@ 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 { - - *r_value = value; - 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) { - + *p_outputs[0]=value; return 0; } @@ -1501,16 +1917,10 @@ public: 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) { - + *p_outputs[0]=singleton; return 0; } @@ -1523,6 +1933,19 @@ VisualScriptNodeInstance* VisualScriptEngineSingleton::instance(VisualScriptInst return instance; } +VisualScriptEngineSingleton::TypeGuess VisualScriptEngineSingleton::guess_output_type(TypeGuess* p_inputs, int p_output) const { + + Object *obj=Globals::get_singleton()->get_singleton_object(singleton); + TypeGuess tg; + tg.type=Variant::OBJECT; + if (obj) { + tg.obj_type=obj->get_type(); + tg.script=obj->get_script(); + } + + return tg; +} + void VisualScriptEngineSingleton::_bind_methods() { @@ -1623,28 +2046,26 @@ public: NodePath path; //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 { + + 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) { Node* node = instance->get_owner_ptr()->cast_to<Node>(); if (!node) { - r_error="Base object is not a Node!"; - return false; + 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(path); if (!node) { - r_error="Path does not lead Node!"; - return false; + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Path does not lead Node!"; + return 0; } - *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) { + *p_outputs[0]=another; return 0; } @@ -1662,6 +2083,8 @@ VisualScriptNodeInstance* VisualScriptSceneNode::instance(VisualScriptInstance* } + + #ifdef TOOLS_ENABLED static Node* _find_script_node(Node* p_edited_scene,Node* p_current_node,const Ref<Script> &script) { @@ -1685,6 +2108,49 @@ static Node* _find_script_node(Node* p_edited_scene,Node* p_current_node,const R #endif +VisualScriptSceneNode::TypeGuess VisualScriptSceneNode::guess_output_type(TypeGuess* p_inputs, int p_output) const { + + + VisualScriptSceneNode::TypeGuess tg; + tg.type=Variant::OBJECT; + tg.obj_type="Node"; + +#ifdef TOOLS_ENABLED + Ref<Script> script = get_visual_script(); + if (!script.is_valid()) + return tg; + + MainLoop * main_loop = OS::get_singleton()->get_main_loop(); + if (!main_loop) + return tg; + + SceneTree *scene_tree = main_loop->cast_to<SceneTree>(); + + if (!scene_tree) + return tg; + + Node *edited_scene = scene_tree->get_edited_scene_root(); + + if (!edited_scene) + return tg; + + Node* script_node = _find_script_node(edited_scene,edited_scene,script); + + if (!script_node) + return tg; + + Node* another = script_node->get_node(path); + + if (another) { + tg.obj_type=another->get_type(); + tg.script=another->get_script(); + } +#endif + return tg; + +} + + void VisualScriptSceneNode::_validate_property(PropertyInfo& property) const { #ifdef TOOLS_ENABLED @@ -1789,28 +2255,24 @@ 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 { + + 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) { Node* node = instance->get_owner_ptr()->cast_to<Node>(); if (!node) { - r_error="Base object is not a Node!"; - return false; + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Base object is not a Node!"; + return 0; } SceneTree* tree = node->get_tree(); if (!tree) { - r_error="Attempt to get SceneTree while node is not in the active tree."; - return false; + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + r_error_str="Attempt to get SceneTree while node is not in the active tree."; + return 0; } - *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) { - + *p_outputs[0]=tree; return 0; } @@ -1826,6 +2288,13 @@ VisualScriptNodeInstance* VisualScriptSceneTree::instance(VisualScriptInstance* return instance; } +VisualScriptSceneTree::TypeGuess VisualScriptSceneTree::guess_output_type(TypeGuess* p_inputs, int p_output) const { + + TypeGuess tg; + tg.type=Variant::OBJECT; + tg.obj_type="SceneTree"; + return tg; +} void VisualScriptSceneTree::_validate_property(PropertyInfo& property) const { @@ -1907,14 +2376,10 @@ public: String path; //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) { + *p_outputs[0] = path; return 0; } @@ -2004,15 +2469,10 @@ 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) { + *p_outputs[0] = instance->get_owner_ptr(); return 0; } @@ -2026,6 +2486,23 @@ VisualScriptNodeInstance* VisualScriptSelf::instance(VisualScriptInstance* p_ins return instance; } +VisualScriptSelf::TypeGuess VisualScriptSelf::guess_output_type(TypeGuess* p_inputs, int p_output) const { + + VisualScriptSceneNode::TypeGuess tg; + tg.type=Variant::OBJECT; + tg.obj_type="Object"; + + Ref<Script> script = get_visual_script(); + if (!script.is_valid()) + return tg; + + tg.obj_type=script->get_instance_base_type(); + tg.script=script; + + return tg; + + +} void VisualScriptSelf::_bind_methods() { @@ -2138,35 +2615,8 @@ public: 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()) { @@ -2239,10 +2689,6 @@ VisualScriptNodeInstance* VisualScriptCustomNode::instance(VisualScriptInstance* 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"); @@ -2275,8 +2721,6 @@ void VisualScriptCustomNode::_bind_methods() { 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 ); @@ -2388,8 +2832,6 @@ public: 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) { @@ -2432,23 +2874,1016 @@ VisualScriptSubCall::VisualScriptSubCall() { } +////////////////////////////////////////// +////////////////Comment/////////// +////////////////////////////////////////// + +int VisualScriptComment::get_output_sequence_port_count() const { + + return 0; +} + +bool VisualScriptComment::has_input_sequence_port() const{ + + return false; +} + +int VisualScriptComment::get_input_value_port_count() const{ + return 0; +} +int VisualScriptComment::get_output_value_port_count() const{ + + return 0; +} + +String VisualScriptComment::get_output_sequence_port_text(int p_port) const { + + return String(); +} + +PropertyInfo VisualScriptComment::get_input_value_port_info(int p_idx) const{ + + return PropertyInfo(); +} + +PropertyInfo VisualScriptComment::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(); +} + + +String VisualScriptComment::get_caption() const { + + return title; +} + + +String VisualScriptComment::get_text() const { + + return description; +} + +void VisualScriptComment::set_title(const String& p_title) { + + + if (title==p_title) + return; + title=p_title; + ports_changed_notify(); +} + +String VisualScriptComment::get_title() const{ + + return title; +} + +void VisualScriptComment::set_description(const String& p_description){ + + if (description==p_description) + return; + description=p_description; + ports_changed_notify(); + +} +String VisualScriptComment::get_description() const{ + + return description; +} + +void VisualScriptComment::set_size(const Size2& p_size){ + + if (size==p_size) + return; + size=p_size; + ports_changed_notify(); + +} +Size2 VisualScriptComment::get_size() const{ + + return size; +} + + +String VisualScriptComment::get_category() const { + + return "data"; +} + +class VisualScriptNodeInstanceComment : public VisualScriptNodeInstance { +public: + + VisualScriptInstance* instance; + + //virtual int get_working_memory_size() const { return 0; } + + virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) { + + + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptComment::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceComment * instance = memnew(VisualScriptNodeInstanceComment ); + instance->instance=p_instance; + return instance; +} + + + +void VisualScriptComment::_bind_methods() { + + + ObjectTypeDB::bind_method(_MD("set_title","title"),&VisualScriptComment::set_title); + ObjectTypeDB::bind_method(_MD("get_title"),&VisualScriptComment::get_title); + + ObjectTypeDB::bind_method(_MD("set_description","description"),&VisualScriptComment::set_description); + ObjectTypeDB::bind_method(_MD("get_description"),&VisualScriptComment::get_description); + + ObjectTypeDB::bind_method(_MD("set_size","size"),&VisualScriptComment::set_size); + ObjectTypeDB::bind_method(_MD("get_size"),&VisualScriptComment::get_size); + + ADD_PROPERTY( PropertyInfo(Variant::STRING,"title"),_SCS("set_title"),_SCS("get_title")); + ADD_PROPERTY( PropertyInfo(Variant::STRING,"description",PROPERTY_HINT_MULTILINE_TEXT),_SCS("set_description"),_SCS("get_description")); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"size"),_SCS("set_size"),_SCS("get_size")); + +} + +VisualScriptComment::VisualScriptComment() { + + title="Comment"; + size=Size2(150,150); +} + + +////////////////////////////////////////// +////////////////Constructor/////////// +////////////////////////////////////////// + +int VisualScriptConstructor::get_output_sequence_port_count() const { + + return 0; +} + +bool VisualScriptConstructor::has_input_sequence_port() const{ + + return false; +} + +int VisualScriptConstructor::get_input_value_port_count() const{ + return constructor.arguments.size(); +} +int VisualScriptConstructor::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptConstructor::get_output_sequence_port_text(int p_port) const { + + return ""; +} + +PropertyInfo VisualScriptConstructor::get_input_value_port_info(int p_idx) const{ + + return constructor.arguments[p_idx]; +} + +PropertyInfo VisualScriptConstructor::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(type,"value"); +} + + +String VisualScriptConstructor::get_caption() const { + + return "Construct"; +} + + +String VisualScriptConstructor::get_text() const { + + return "new "+Variant::get_type_name(type)+"()"; +} + + +String VisualScriptConstructor::get_category() const { + + return "functions"; +} + +void VisualScriptConstructor::set_constructor_type(Variant::Type p_type) { + + if (type==p_type) + return; + + type=p_type; + ports_changed_notify(); +} + +Variant::Type VisualScriptConstructor::get_constructor_type() const { + + return type; +} + +void VisualScriptConstructor::set_constructor(const Dictionary& p_info) { + + constructor=MethodInfo::from_dict(p_info); + ports_changed_notify(); +} + +Dictionary VisualScriptConstructor::get_constructor() const { + + return constructor; +} + + +class VisualScriptNodeInstanceConstructor : public VisualScriptNodeInstance { +public: + + VisualScriptInstance* instance; + Variant::Type type; + int argcount; + + //virtual int get_working_memory_size() const { return 0; } + + 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) { + + Variant::CallError ce; + *p_outputs[0]=Variant::construct(type,p_inputs,argcount,ce); + if (ce.error!=Variant::CallError::CALL_OK) { + r_error_str="Invalid arguments for constructor"; + } + + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptConstructor::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceConstructor * instance = memnew(VisualScriptNodeInstanceConstructor ); + instance->instance=p_instance; + instance->type=type; + instance->argcount=constructor.arguments.size(); + return instance; +} + + + +void VisualScriptConstructor::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_constructor_type","type"),&VisualScriptConstructor::set_constructor_type); + ObjectTypeDB::bind_method(_MD("get_constructor_type"),&VisualScriptConstructor::get_constructor_type); + + ObjectTypeDB::bind_method(_MD("set_constructor","constructor"),&VisualScriptConstructor::set_constructor); + ObjectTypeDB::bind_method(_MD("get_constructor"),&VisualScriptConstructor::get_constructor); + + ADD_PROPERTY( PropertyInfo(Variant::INT,"type",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_constructor_type"),_SCS("get_constructor_type")); + ADD_PROPERTY( PropertyInfo(Variant::DICTIONARY,"constructor",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_constructor"),_SCS("get_constructor")); + +} + +VisualScriptConstructor::VisualScriptConstructor() { + + type=Variant::NIL; + +} + +static Map<String,Pair<Variant::Type,MethodInfo> > constructor_map; + +static Ref<VisualScriptNode> create_constructor_node(const String& p_name) { + + ERR_FAIL_COND_V(!constructor_map.has(p_name),Ref<VisualScriptNode>()); + + Ref<VisualScriptConstructor> vsc; + vsc.instance(); + vsc->set_constructor_type(constructor_map[p_name].first); + vsc->set_constructor(constructor_map[p_name].second); + + return vsc; +} + +////////////////////////////////////////// +////////////////LocalVar/////////// +////////////////////////////////////////// + +int VisualScriptLocalVar::get_output_sequence_port_count() const { + + return 0; +} + +bool VisualScriptLocalVar::has_input_sequence_port() const{ + + return false; +} + +int VisualScriptLocalVar::get_input_value_port_count() const{ + return 0; +} +int VisualScriptLocalVar::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptLocalVar::get_output_sequence_port_text(int p_port) const { + + return ""; +} + +PropertyInfo VisualScriptLocalVar::get_input_value_port_info(int p_idx) const{ + + return PropertyInfo(); +} +PropertyInfo VisualScriptLocalVar::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(type,"get"); +} + + +String VisualScriptLocalVar::get_caption() const { + + return "LocalVarGet"; +} + + +String VisualScriptLocalVar::get_text() const { + + return name; +} + + +String VisualScriptLocalVar::get_category() const { + + return "data"; +} + + +void VisualScriptLocalVar::set_var_name(const StringName& p_name) { + + if (name==p_name) + return; + + name=p_name; + ports_changed_notify(); + +} + +StringName VisualScriptLocalVar::get_var_name() const { + + return name; +} + +void VisualScriptLocalVar::set_var_type(Variant::Type p_type) { + + type=p_type; + ports_changed_notify(); +} + +Variant::Type VisualScriptLocalVar::get_var_type() const { + + return type; +} + + +class VisualScriptNodeInstanceLocalVar : public VisualScriptNodeInstance { +public: + + VisualScriptInstance* instance; + StringName name; + + + virtual int get_working_memory_size() const { return 1; } + 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) { + + *p_outputs[0]=*p_working_mem; + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptLocalVar::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceLocalVar * instance = memnew(VisualScriptNodeInstanceLocalVar ); + instance->instance=p_instance; + instance->name=name; + + return instance; +} + + + +void VisualScriptLocalVar::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_var_name","name"),&VisualScriptLocalVar::set_var_name); + ObjectTypeDB::bind_method(_MD("get_var_name"),&VisualScriptLocalVar::get_var_name); + + ObjectTypeDB::bind_method(_MD("set_var_type","type"),&VisualScriptLocalVar::set_var_type); + ObjectTypeDB::bind_method(_MD("get_var_type"),&VisualScriptLocalVar::get_var_type); + + String argt="Any"; + for(int i=1;i<Variant::VARIANT_MAX;i++) { + argt+=","+Variant::get_type_name(Variant::Type(i)); + } + + ADD_PROPERTY( PropertyInfo(Variant::STRING,"variable/name"),_SCS("set_var_name"),_SCS("get_var_name")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"variable/type",PROPERTY_HINT_ENUM,argt),_SCS("set_var_type"),_SCS("get_var_type")); + + +} + +VisualScriptLocalVar::VisualScriptLocalVar() { + + name="new_local"; + type=Variant::NIL; + +} + +////////////////////////////////////////// +////////////////LocalVar/////////// +////////////////////////////////////////// + +int VisualScriptLocalVarSet::get_output_sequence_port_count() const { + + return 1; +} + +bool VisualScriptLocalVarSet::has_input_sequence_port() const{ + + return true; +} + +int VisualScriptLocalVarSet::get_input_value_port_count() const{ + return 1; +} +int VisualScriptLocalVarSet::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptLocalVarSet::get_output_sequence_port_text(int p_port) const { + + return ""; +} + +PropertyInfo VisualScriptLocalVarSet::get_input_value_port_info(int p_idx) const{ + + return PropertyInfo(type,"set"); +} +PropertyInfo VisualScriptLocalVarSet::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(type,"get"); +} + + +String VisualScriptLocalVarSet::get_caption() const { + + return "LocalVarSet"; +} + + +String VisualScriptLocalVarSet::get_text() const { + + return name; +} + + +String VisualScriptLocalVarSet::get_category() const { + + return "data"; +} + + +void VisualScriptLocalVarSet::set_var_name(const StringName& p_name) { + + if (name==p_name) + return; + + name=p_name; + ports_changed_notify(); + +} + +StringName VisualScriptLocalVarSet::get_var_name() const { + + return name; +} + +void VisualScriptLocalVarSet::set_var_type(Variant::Type p_type) { + + type=p_type; + ports_changed_notify(); +} + +Variant::Type VisualScriptLocalVarSet::get_var_type() const { + + return type; +} + + +class VisualScriptNodeInstanceLocalVarSet : public VisualScriptNodeInstance { +public: + + VisualScriptInstance* instance; + StringName name; + + + virtual int get_working_memory_size() const { return 1; } + 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) { + + *p_working_mem=*p_inputs[0]; + *p_outputs[0]=*p_working_mem; + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptLocalVarSet::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceLocalVarSet * instance = memnew(VisualScriptNodeInstanceLocalVarSet ); + instance->instance=p_instance; + instance->name=name; + + return instance; +} + + + +void VisualScriptLocalVarSet::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_var_name","name"),&VisualScriptLocalVarSet::set_var_name); + ObjectTypeDB::bind_method(_MD("get_var_name"),&VisualScriptLocalVarSet::get_var_name); + + ObjectTypeDB::bind_method(_MD("set_var_type","type"),&VisualScriptLocalVarSet::set_var_type); + ObjectTypeDB::bind_method(_MD("get_var_type"),&VisualScriptLocalVarSet::get_var_type); + + String argt="Any"; + for(int i=1;i<Variant::VARIANT_MAX;i++) { + argt+=","+Variant::get_type_name(Variant::Type(i)); + } + + ADD_PROPERTY( PropertyInfo(Variant::STRING,"variable/name"),_SCS("set_var_name"),_SCS("get_var_name")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"variable/type",PROPERTY_HINT_ENUM,argt),_SCS("set_var_type"),_SCS("get_var_type")); + + +} + +VisualScriptLocalVarSet::VisualScriptLocalVarSet() { + + name="new_local"; + type=Variant::NIL; + +} + + +////////////////////////////////////////// +////////////////LocalVar/////////// +////////////////////////////////////////// + +int VisualScriptInputAction::get_output_sequence_port_count() const { + + return 0; +} + +bool VisualScriptInputAction::has_input_sequence_port() const{ + + return false; +} + +int VisualScriptInputAction::get_input_value_port_count() const{ + return 0; +} +int VisualScriptInputAction::get_output_value_port_count() const{ + + return 1; +} + +String VisualScriptInputAction::get_output_sequence_port_text(int p_port) const { + + return ""; +} + +PropertyInfo VisualScriptInputAction::get_input_value_port_info(int p_idx) const{ + + return PropertyInfo(); +} +PropertyInfo VisualScriptInputAction::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(Variant::BOOL,"pressed"); +} + + +String VisualScriptInputAction::get_caption() const { + + + return "Action"; +} + + +String VisualScriptInputAction::get_text() const { + + switch(mode) { + case MODE_PRESSED: { + return name; + } break; + case MODE_RELEASED: { + return "not "+name; + } break; + case MODE_JUST_PRESSED: { + return String(name)+" "+TTR("just pressed"); + } break; + case MODE_JUST_RELEASED: { + return String(name)+" "+TTR("just released"); + } break; + } + + return String(); +} + + +String VisualScriptInputAction::get_category() const { + + return "data"; +} + + +void VisualScriptInputAction::set_action_name(const StringName& p_name) { + + if (name==p_name) + return; + + name=p_name; + ports_changed_notify(); + +} + +StringName VisualScriptInputAction::get_action_name() const { + + return name; +} + +void VisualScriptInputAction::set_action_mode(Mode p_mode) { + + if (mode==p_mode) + return; + + mode=p_mode; + ports_changed_notify(); + +} +VisualScriptInputAction::Mode VisualScriptInputAction::get_action_mode() const { + + return mode; +} + + +class VisualScriptNodeInstanceInputAction : public VisualScriptNodeInstance { +public: + + VisualScriptInstance* instance; + StringName action; + VisualScriptInputAction::Mode mode; + + + virtual int get_working_memory_size() const { return 1; } + + 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(mode) { + case VisualScriptInputAction::MODE_PRESSED: { + *p_outputs[0]=Input::get_singleton()->is_action_pressed(action); + } break; + case VisualScriptInputAction::MODE_RELEASED: { + *p_outputs[0]=!Input::get_singleton()->is_action_pressed(action); + } break; + case VisualScriptInputAction::MODE_JUST_PRESSED: { + *p_outputs[0]=Input::get_singleton()->is_action_just_pressed(action); + } break; + case VisualScriptInputAction:: MODE_JUST_RELEASED: { + *p_outputs[0]=Input::get_singleton()->is_action_just_released(action); + } break; + + } + + + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptInputAction::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceInputAction * instance = memnew(VisualScriptNodeInstanceInputAction ); + instance->instance=p_instance; + instance->action=name; + instance->mode=mode; + + return instance; +} + +void VisualScriptInputAction::_validate_property(PropertyInfo& property) const { + + + if (property.name=="action") { + + property.hint=PROPERTY_HINT_ENUM; + String actions; + + 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); + } + + al.sort();; + + for(int i=0;i<al.size();i++) { + if (actions!=String()) + actions+=","; + actions+=al[i]; + } + + property.hint_string=actions; + } +} + + +void VisualScriptInputAction::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_action_name","name"),&VisualScriptInputAction::set_action_name); + ObjectTypeDB::bind_method(_MD("get_action_name"),&VisualScriptInputAction::get_action_name); + + ObjectTypeDB::bind_method(_MD("set_action_mode","mode"),&VisualScriptInputAction::set_action_mode); + ObjectTypeDB::bind_method(_MD("get_action_mode"),&VisualScriptInputAction::get_action_mode); + + ADD_PROPERTY( PropertyInfo(Variant::STRING,"action"),_SCS("set_action_name"),_SCS("get_action_name")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"mode",PROPERTY_HINT_ENUM,"Pressed,Released,JustPressed,JustReleased"),_SCS("set_action_mode"),_SCS("get_action_mode")); + +} + +VisualScriptInputAction::VisualScriptInputAction() { + + name=""; + mode=MODE_PRESSED; + +} + +////////////////////////////////////////// +////////////////Constructor/////////// +////////////////////////////////////////// + +int VisualScriptDeconstruct::get_output_sequence_port_count() const { + + return 0; +} + +bool VisualScriptDeconstruct::has_input_sequence_port() const{ + + return false; +} + +int VisualScriptDeconstruct::get_input_value_port_count() const{ + return 1; +} +int VisualScriptDeconstruct::get_output_value_port_count() const{ + + return elements.size(); +} + +String VisualScriptDeconstruct::get_output_sequence_port_text(int p_port) const { + + return ""; +} + +PropertyInfo VisualScriptDeconstruct::get_input_value_port_info(int p_idx) const{ + + return PropertyInfo(type,"value"); +} + +PropertyInfo VisualScriptDeconstruct::get_output_value_port_info(int p_idx) const{ + + return PropertyInfo(elements[p_idx].type,elements[p_idx].name); +} + + +String VisualScriptDeconstruct::get_caption() const { + + return "Deconstruct"; +} + + +String VisualScriptDeconstruct::get_text() const { + + return "from "+Variant::get_type_name(type)+":"; +} + + +String VisualScriptDeconstruct::get_category() const { + + return "functions"; +} + +void VisualScriptDeconstruct::_update_elements() { + + elements.clear();; + Variant v; + if (type==Variant::INPUT_EVENT) { + InputEvent ie; + ie.type=input_type; + v=ie; + } else { + Variant::CallError ce; + v = Variant::construct(type,NULL,0,ce); + } + + List<PropertyInfo> pinfo; + v.get_property_list(&pinfo); + + for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { + + Element e; + e.name=E->get().name; + e.type=E->get().type; + elements.push_back(e); + } +} + +void VisualScriptDeconstruct::set_deconstruct_type(Variant::Type p_type) { + + if (type==p_type) + return; + + type=p_type; + _update_elements(); + ports_changed_notify(); + _change_notify(); //to make input appear/disappear +} + +Variant::Type VisualScriptDeconstruct::get_deconstruct_type() const { + + return type; +} + +void VisualScriptDeconstruct::set_deconstruct_input_type(InputEvent::Type p_input_type) { + + if (input_type==p_input_type) + return; + + input_type=p_input_type; + _update_elements(); + ports_changed_notify(); +} + +InputEvent::Type VisualScriptDeconstruct::get_deconstruct_input_type() const { + + return input_type; +} + +void VisualScriptDeconstruct::_set_elem_cache(const Array& p_elements) { + + ERR_FAIL_COND(p_elements.size()%2==1); + elements.resize(p_elements.size()/2); + for(int i=0;i<elements.size();i++) { + elements[i].name=p_elements[i*2+0]; + elements[i].type=Variant::Type(int(p_elements[i*2+1])); + } +} + +Array VisualScriptDeconstruct::_get_elem_cache() const { + + Array ret; + for(int i=0;i<elements.size();i++) { + ret.push_back(elements[i].name); + ret.push_back(elements[i].type); + } + return ret; +} + +class VisualScriptNodeInstanceDeconstruct : public VisualScriptNodeInstance { +public: + + VisualScriptInstance* instance; + Vector<StringName> outputs; + + //virtual int get_working_memory_size() const { return 0; } + + 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) { + + Variant in=*p_inputs[0]; + + for(int i=0;i<outputs.size();i++) { + bool valid; + *p_outputs[i]=in.get(outputs[i],&valid); + if (!valid) { + r_error_str="Can't obtain element '"+String(outputs[i])+"' from "+Variant::get_type_name(in.get_type()); + r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; + return 0; + } + + } + + return 0; + } + + +}; + +VisualScriptNodeInstance* VisualScriptDeconstruct::instance(VisualScriptInstance* p_instance) { + + VisualScriptNodeInstanceDeconstruct * instance = memnew(VisualScriptNodeInstanceDeconstruct ); + instance->instance=p_instance; + instance->outputs.resize(elements.size()); + for(int i=0;i<elements.size();i++) { + instance->outputs[i]=elements[i].name; + } + + return instance; +} + + + +void VisualScriptDeconstruct::_validate_property(PropertyInfo& property) const { + + if (property.name=="input_type") { + if (type!=Variant::INPUT_EVENT) { + property.usage=0; + } + } +} + + +void VisualScriptDeconstruct::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_deconstruct_type","type"),&VisualScriptDeconstruct::set_deconstruct_type); + ObjectTypeDB::bind_method(_MD("get_deconstruct_type"),&VisualScriptDeconstruct::get_deconstruct_type); + + ObjectTypeDB::bind_method(_MD("set_deconstruct_input_type","input_type"),&VisualScriptDeconstruct::set_deconstruct_input_type); + ObjectTypeDB::bind_method(_MD("get_deconstruct_input_type"),&VisualScriptDeconstruct::get_deconstruct_input_type); + + ObjectTypeDB::bind_method(_MD("_set_elem_cache","_cache"),&VisualScriptDeconstruct::_set_elem_cache); + ObjectTypeDB::bind_method(_MD("_get_elem_cache"),&VisualScriptDeconstruct::_get_elem_cache); + + String argt="Any"; + for(int i=1;i<Variant::VARIANT_MAX;i++) { + argt+=","+Variant::get_type_name(Variant::Type(i)); + } + + String iet="None,Key,MouseMotion,MouseButton,JoystickMotion,JoystickButton,ScreenTouch,ScreenDrag,Action"; + + ADD_PROPERTY( PropertyInfo(Variant::INT,"type",PROPERTY_HINT_ENUM,argt),_SCS("set_deconstruct_type"),_SCS("get_deconstruct_type")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"input_type",PROPERTY_HINT_ENUM,iet),_SCS("set_deconstruct_input_type"),_SCS("get_deconstruct_input_type")); + ADD_PROPERTY( PropertyInfo(Variant::ARRAY,"elem_cache",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_elem_cache"),_SCS("_get_elem_cache")); + +} + +VisualScriptDeconstruct::VisualScriptDeconstruct() { + + type=Variant::NIL; + input_type=InputEvent::NONE; + +} + void register_visual_script_nodes() { - 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>); + VisualScriptLanguage::singleton->add_register_func("data/set_variable",create_node_generic<VisualScriptVariableSet>); + VisualScriptLanguage::singleton->add_register_func("data/get_variable",create_node_generic<VisualScriptVariableGet>); VisualScriptLanguage::singleton->add_register_func("data/engine_singleton",create_node_generic<VisualScriptEngineSingleton>); 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("data/comment",create_node_generic<VisualScriptComment>); + VisualScriptLanguage::singleton->add_register_func("data/get_local_variable",create_node_generic<VisualScriptLocalVar>); + VisualScriptLanguage::singleton->add_register_func("data/set_local_variable",create_node_generic<VisualScriptLocalVarSet>); + VisualScriptLanguage::singleton->add_register_func("data/preload",create_node_generic<VisualScriptPreload>); + VisualScriptLanguage::singleton->add_register_func("data/action",create_node_generic<VisualScriptInputAction>); + + VisualScriptLanguage::singleton->add_register_func("constants/constant",create_node_generic<VisualScriptConstant>); + VisualScriptLanguage::singleton->add_register_func("constants/math_constant",create_node_generic<VisualScriptMathConstant>); + VisualScriptLanguage::singleton->add_register_func("constants/class_constant",create_node_generic<VisualScriptClassConstant>); + VisualScriptLanguage::singleton->add_register_func("constants/global_constant",create_node_generic<VisualScriptGlobalConstant>); + VisualScriptLanguage::singleton->add_register_func("constants/basic_type_constant",create_node_generic<VisualScriptBasicTypeConstant>); + 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>); VisualScriptLanguage::singleton->add_register_func("index/set_index",create_node_generic<VisualScriptIndexSet>); @@ -2481,5 +3916,43 @@ 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>); + VisualScriptLanguage::singleton->add_register_func("functions/deconstruct",create_node_generic<VisualScriptDeconstruct>); + for(int i=1;i<Variant::VARIANT_MAX;i++) { + + List<MethodInfo> constructors; + Variant::get_constructor_list(Variant::Type(i),&constructors); + + for(List<MethodInfo>::Element *E=constructors.front();E;E=E->next()) { + + if (E->get().arguments.size()>0) { + + + String name = "functions/constructors/"+Variant::get_type_name(Variant::Type(i))+" ( "; + for(int j=0;j<E->get().arguments.size();j++) { + if (j>0) + name+=", "; + if (E->get().arguments.size()==1) + name+=Variant::get_type_name(E->get().arguments[j].type); + else + name+=E->get().arguments[j].name; + } + name+=") "; + + VisualScriptLanguage::singleton->add_register_func(name,create_constructor_node); + Pair<Variant::Type,MethodInfo> pair; + pair.first=Variant::Type(i); + pair.second=E->get(); + constructor_map[name]=pair; + } + } + } +} + + + +void unregister_visual_script_nodes() { + + constructor_map.clear(); } + diff --git a/modules/visual_script/visual_script_nodes.h b/modules/visual_script/visual_script_nodes.h index 50f61ecfcc..94eeadca57 100644 --- a/modules/visual_script/visual_script_nodes.h +++ b/modules/visual_script/visual_script_nodes.h @@ -17,6 +17,7 @@ class VisualScriptFunction : public VisualScriptNode { bool stack_less; int stack_size; + ScriptInstance::RPCMode rpc_mode; protected: @@ -60,6 +61,9 @@ public: void set_stack_size(int p_size); int get_stack_size() const; + void set_rpc_mode(ScriptInstance::RPCMode p_mode); + ScriptInstance::RPCMode get_rpc_mode() const; + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); VisualScriptFunction(); @@ -71,6 +75,7 @@ class VisualScriptOperator : public VisualScriptNode { OBJ_TYPE(VisualScriptOperator,VisualScriptNode) + Variant::Type typed; Variant::Operator op; protected: @@ -98,6 +103,9 @@ public: void set_operator(Variant::Operator p_op); Variant::Operator get_operator() const; + void set_typed(Variant::Type p_op); + Variant::Type get_typed() const; + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); VisualScriptOperator(); @@ -211,7 +219,7 @@ public: virtual String get_caption() const; virtual String get_text() const; - virtual String get_category() const { return "data"; } + virtual String get_category() const { return "constants"; } void set_constant_type(Variant::Type p_type); Variant::Type get_constant_type() const; @@ -225,6 +233,45 @@ public: }; + +class VisualScriptPreload : public VisualScriptNode { + + OBJ_TYPE(VisualScriptPreload,VisualScriptNode) + + + Ref<Resource> preload; +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"; } + + void set_preload(const Ref<Resource>& p_value); + Ref<Resource> get_preload() const; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptPreload(); +}; + class VisualScriptIndexGet : public VisualScriptNode { OBJ_TYPE(VisualScriptIndexGet,VisualScriptNode) @@ -313,7 +360,7 @@ public: virtual String get_caption() const; virtual String get_text() const; - virtual String get_category() const { return "data"; } + virtual String get_category() const { return "constants"; } void set_global_constant(int p_which); int get_global_constant(); @@ -324,6 +371,89 @@ public: }; +class VisualScriptClassConstant : public VisualScriptNode { + + OBJ_TYPE(VisualScriptClassConstant,VisualScriptNode) + + StringName base_type; + StringName name; +protected: + static void _bind_methods(); + virtual void _validate_property(PropertyInfo& property) 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 "constants"; } + + void set_class_constant(const StringName& p_which); + StringName get_class_constant(); + + void set_base_type(const StringName& p_which); + StringName get_base_type(); + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptClassConstant(); +}; + +class VisualScriptBasicTypeConstant : public VisualScriptNode { + + OBJ_TYPE(VisualScriptBasicTypeConstant,VisualScriptNode) + + Variant::Type type; + StringName name; +protected: + static void _bind_methods(); + virtual void _validate_property(PropertyInfo& property) 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 "constants"; } + + void set_basic_type_constant(const StringName& p_which); + StringName get_basic_type_constant() const; + + void set_basic_type(Variant::Type p_which); + Variant::Type get_basic_type() const; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptBasicTypeConstant(); +}; + + class VisualScriptMathConstant : public VisualScriptNode { @@ -364,7 +494,7 @@ public: virtual String get_caption() const; virtual String get_text() const; - virtual String get_category() const { return "data"; } + virtual String get_category() const { return "constants"; } void set_math_constant(MathConstant p_which); MathConstant get_math_constant(); @@ -408,6 +538,9 @@ public: virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + virtual TypeGuess guess_output_type(TypeGuess* p_inputs, int p_output) const; + + VisualScriptEngineSingleton(); }; @@ -447,6 +580,8 @@ public: virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + virtual TypeGuess guess_output_type(TypeGuess* p_inputs, int p_output) const; + VisualScriptSceneNode(); }; @@ -483,6 +618,8 @@ public: virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + virtual TypeGuess guess_output_type(TypeGuess* p_inputs, int p_output) const; + VisualScriptSceneTree(); }; @@ -556,6 +693,8 @@ public: virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + virtual TypeGuess guess_output_type(TypeGuess* p_inputs, int p_output) const; + VisualScriptSelf(); }; @@ -618,7 +757,6 @@ class VisualScriptSubCall: public VisualScriptNode { protected: - virtual bool _use_builtin_script() const { return true; } static void _bind_methods(); public: @@ -645,7 +783,286 @@ public: VisualScriptSubCall(); }; +class VisualScriptComment: public VisualScriptNode { + + OBJ_TYPE(VisualScriptComment,VisualScriptNode) + + + String title; + String description; + Size2 size; +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; + + void set_title(const String& p_title); + String get_title() const; + + void set_description(const String& p_description); + String get_description() const; + + void set_size(const Size2& p_size); + Size2 get_size() const; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptComment(); +}; + +class VisualScriptConstructor: public VisualScriptNode { + + OBJ_TYPE(VisualScriptConstructor,VisualScriptNode) + + + Variant::Type type; + MethodInfo constructor; + +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; + + void set_constructor_type(Variant::Type p_type); + Variant::Type get_constructor_type() const; + + void set_constructor(const Dictionary& p_info); + Dictionary get_constructor() const; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptConstructor(); +}; + + + + +class VisualScriptLocalVar: public VisualScriptNode { + + OBJ_TYPE(VisualScriptLocalVar,VisualScriptNode) + + StringName name; + Variant::Type type; + +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; + + void set_var_name(const StringName& p_name); + StringName get_var_name() const; + + void set_var_type(Variant::Type p_type); + Variant::Type get_var_type() const; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptLocalVar(); +}; + +class VisualScriptLocalVarSet: public VisualScriptNode { + + OBJ_TYPE(VisualScriptLocalVarSet,VisualScriptNode) + + StringName name; + Variant::Type type; + +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; + + void set_var_name(const StringName& p_name); + StringName get_var_name() const; + + void set_var_type(Variant::Type p_type); + Variant::Type get_var_type() const; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptLocalVarSet(); +}; + + + +class VisualScriptInputAction: public VisualScriptNode { + + OBJ_TYPE(VisualScriptInputAction,VisualScriptNode) +public: + enum Mode { + MODE_PRESSED, + MODE_RELEASED, + MODE_JUST_PRESSED, + MODE_JUST_RELEASED, + }; + + StringName name; + Mode mode; + +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; + + void set_action_name(const StringName& p_name); + StringName get_action_name() const; + + void set_action_mode(Mode p_mode); + Mode get_action_mode() const; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptInputAction(); +}; + +VARIANT_ENUM_CAST( VisualScriptInputAction::Mode ) + +class VisualScriptDeconstruct: public VisualScriptNode { + + OBJ_TYPE(VisualScriptDeconstruct,VisualScriptNode) + + + struct Element { + StringName name; + Variant::Type type; + }; + + + Vector<Element> elements; + + void _update_elements(); + Variant::Type type; + InputEvent::Type input_type; + + void _set_elem_cache(const Array& p_elements); + Array _get_elem_cache() const; + + virtual void _validate_property(PropertyInfo& property) const; + +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; + + void set_deconstruct_type(Variant::Type p_type); + Variant::Type get_deconstruct_type() const; + + void set_deconstruct_input_type(InputEvent::Type p_input_type); + InputEvent::Type get_deconstruct_input_type() const; + + virtual VisualScriptNodeInstance* instance(VisualScriptInstance* p_instance); + + VisualScriptDeconstruct(); +}; + void register_visual_script_nodes(); +void unregister_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 index 24d5b7cf1a..221c46b6fd 100644 --- a/modules/visual_script/visual_script_yield_nodes.cpp +++ b/modules/visual_script/visual_script_yield_nodes.cpp @@ -45,12 +45,13 @@ PropertyInfo VisualScriptYield::get_output_value_port_info(int p_idx) const{ String VisualScriptYield::get_caption() const { - return "Wait"; + return yield_mode==YIELD_RETURN?"Yield":"Wait"; } String VisualScriptYield::get_text() const { switch (yield_mode) { + case YIELD_RETURN: return ""; break; case YIELD_FRAME: return "Next Frame"; break; case YIELD_FIXED_FRAME: return "Next Fixed Frame"; break; case YIELD_WAIT: return rtos(wait_time)+" sec(s)"; break; @@ -88,8 +89,10 @@ public: Ref<VisualScriptFunctionState> state; state.instance(); + int ret = STEP_YIELD_BIT; switch(mode) { + case VisualScriptYield::YIELD_RETURN: ret=STEP_EXIT_FUNCTION_BIT; break; //return the yield case VisualScriptYield::YIELD_FRAME: state->connect_to_signal(tree,"idle_frame",Array()); break; case VisualScriptYield::YIELD_FIXED_FRAME: state->connect_to_signal(tree,"fixed_frame",Array()); break; case VisualScriptYield::YIELD_WAIT: state->connect_to_signal(tree->create_timer(wait_time).ptr(),"timeout",Array()); break; @@ -98,7 +101,7 @@ public: *p_working_mem=state; - return STEP_YIELD_BIT; + return ret; } } @@ -487,7 +490,7 @@ void VisualScriptYieldSignal::_bind_methods() { bt+=Variant::get_type_name(Variant::Type(i)); } - ADD_PROPERTY(PropertyInfo(Variant::INT,"signal/call_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance",PROPERTY_USAGE_NOEDITOR),_SCS("set_call_mode"),_SCS("get_call_mode")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"signal/call_mode",PROPERTY_HINT_ENUM,"Self,Node Path,Instance"),_SCS("set_call_mode"),_SCS("get_call_mode")); ADD_PROPERTY(PropertyInfo(Variant::STRING,"signal/base_type",PROPERTY_HINT_TYPE_STRING,"Object"),_SCS("set_base_type"),_SCS("get_base_type")); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"signal/node_path",PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE),_SCS("set_base_path"),_SCS("get_base_path")); ADD_PROPERTY(PropertyInfo(Variant::STRING,"signal/signal"),_SCS("set_signal"),_SCS("get_signal")); @@ -615,8 +618,8 @@ void register_visual_script_yield_nodes() { VisualScriptLanguage::singleton->add_register_func("functions/wait/wait_fixed_frame",create_yield_node<VisualScriptYield::YIELD_FIXED_FRAME>); VisualScriptLanguage::singleton->add_register_func("functions/wait/wait_time",create_yield_node<VisualScriptYield::YIELD_WAIT>); - VisualScriptLanguage::singleton->add_register_func("functions/yield/instance_signal",create_yield_signal_node<VisualScriptYieldSignal::CALL_MODE_INSTANCE>); - VisualScriptLanguage::singleton->add_register_func("functions/yield/self_signal",create_yield_signal_node<VisualScriptYieldSignal::CALL_MODE_SELF>); - VisualScriptLanguage::singleton->add_register_func("functions/yield/node_signal",create_yield_signal_node<VisualScriptYieldSignal::CALL_MODE_NODE_PATH>); + + VisualScriptLanguage::singleton->add_register_func("functions/yield",create_yield_node<VisualScriptYield::YIELD_RETURN>); + VisualScriptLanguage::singleton->add_register_func("functions/yield_signal",create_node_generic<VisualScriptYieldSignal>); } diff --git a/modules/visual_script/visual_script_yield_nodes.h b/modules/visual_script/visual_script_yield_nodes.h index a7e200305d..ae7f8c15c1 100644 --- a/modules/visual_script/visual_script_yield_nodes.h +++ b/modules/visual_script/visual_script_yield_nodes.h @@ -9,6 +9,7 @@ class VisualScriptYield : public VisualScriptNode { public: enum YieldMode { + YIELD_RETURN, YIELD_FRAME, YIELD_FIXED_FRAME, YIELD_WAIT |