diff --git a/core/dictionary.cpp b/core/dictionary.cpp index 6204a87054f..6770b798f1c 100644 --- a/core/dictionary.cpp +++ b/core/dictionary.cpp @@ -232,6 +232,20 @@ Error Dictionary::parse_json(const String& p_json) { return OK; } +Dictionary Dictionary::copy() const { + + Dictionary n(is_shared()); + + List keys; + get_key_list(&keys); + + for(List::Element *E=keys.front();E;E=E->next()) { + n[E->get()]=operator[](E->get()); + } + + return n; +} + String Dictionary::to_json() const { return JSON::print(*this); diff --git a/core/dictionary.h b/core/dictionary.h index ae79fab9c38..6a5f4e20e67 100644 --- a/core/dictionary.h +++ b/core/dictionary.h @@ -83,6 +83,8 @@ public: Array keys() const; Array values() const; + Dictionary copy() const; + Dictionary(const Dictionary& p_from); Dictionary(bool p_shared=false); ~Dictionary(); diff --git a/core/io/networked_multiplayer_peer.cpp b/core/io/networked_multiplayer_peer.cpp new file mode 100644 index 00000000000..79f3e129e1a --- /dev/null +++ b/core/io/networked_multiplayer_peer.cpp @@ -0,0 +1,29 @@ +#include "networked_multiplayer_peer.h" + + +void NetworkedMultiplayerPeer::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_transfer_mode","mode"), &NetworkedMultiplayerPeer::set_transfer_mode ); + ObjectTypeDB::bind_method(_MD("set_target_peer","id"), &NetworkedMultiplayerPeer::set_target_peer ); + ObjectTypeDB::bind_method(_MD("set_channel","id"), &NetworkedMultiplayerPeer::set_channel ); + + ObjectTypeDB::bind_method(_MD("get_packet_peer"), &NetworkedMultiplayerPeer::get_packet_peer ); + ObjectTypeDB::bind_method(_MD("get_packet_channel"), &NetworkedMultiplayerPeer::get_packet_channel ); + + ObjectTypeDB::bind_method(_MD("poll"), &NetworkedMultiplayerPeer::poll ); + + + BIND_CONSTANT( TARGET_ALL_PEERS ); + + BIND_CONSTANT( TRANSFER_MODE_UNRELIABLE ); + BIND_CONSTANT( TRANSFER_MODE_RELIABLE ); + BIND_CONSTANT( TRANSFER_MODE_ORDERED ); + + ADD_SIGNAL( MethodInfo("peer_connected",PropertyInfo(Variant::INT,"id"))); + ADD_SIGNAL( MethodInfo("peer_disconnected",PropertyInfo(Variant::INT,"id"))); +} + +NetworkedMultiplayerPeer::NetworkedMultiplayerPeer() { + + +} diff --git a/core/io/networked_multiplayer_peer.h b/core/io/networked_multiplayer_peer.h new file mode 100644 index 00000000000..f140b57b8b2 --- /dev/null +++ b/core/io/networked_multiplayer_peer.h @@ -0,0 +1,40 @@ +#ifndef NETWORKED_MULTIPLAYER_PEER_H +#define NETWORKED_MULTIPLAYER_PEER_H + +#include "io/packet_peer.h" + +class NetworkedMultiplayerPeer : public PacketPeer { + + OBJ_TYPE(NetworkedMultiplayerPeer,PacketPeer); + +protected: + static void _bind_methods(); +public: + + enum { + TARGET_ALL_PEERS=0xFFFFFF // send to this for all peers + }; + + enum TransferMode { + TRANSFER_MODE_UNRELIABLE, + TRANSFER_MODE_RELIABLE, + TRANSFER_MODE_ORDERED + }; + + virtual void set_transfer_mode(TransferMode p_mode)=0; + virtual void set_target_peer(int p_peer)=0; + virtual void set_channel(int p_channel)=0; + + + virtual int get_packet_peer() const=0; + virtual int get_packet_channel() const=0; + + + virtual void poll()=0; + + NetworkedMultiplayerPeer(); +}; + +VARIANT_ENUM_CAST( NetworkedMultiplayerPeer::TransferMode ) + +#endif // NetworkedMultiplayerPeer_H diff --git a/core/make_binders.py b/core/make_binders.py index c14f07ac838..75847229652 100644 --- a/core/make_binders.py +++ b/core/make_binders.py @@ -62,6 +62,8 @@ public: #else set_argument_count($argc$); #endif + + $ifret _set_returns(true); $ }; }; @@ -140,6 +142,9 @@ public: #else set_argument_count($argc$); #endif + $ifret _set_returns(true); $ + + }; }; diff --git a/core/method_bind.cpp b/core/method_bind.cpp index b41fa338875..a99d0af6365 100644 --- a/core/method_bind.cpp +++ b/core/method_bind.cpp @@ -64,6 +64,12 @@ void MethodBind::_set_const(bool p_const) { _const=p_const; } +void MethodBind::_set_returns(bool p_returns) { + + _returns=p_returns; +} + + StringName MethodBind::get_name() const { return name; } @@ -118,6 +124,7 @@ MethodBind::MethodBind() { argument_types=NULL; #endif _const=false; + _returns=false; } MethodBind::~MethodBind() { diff --git a/core/method_bind.h b/core/method_bind.h index 30a848270d8..3d62e38daa6 100644 --- a/core/method_bind.h +++ b/core/method_bind.h @@ -154,6 +154,8 @@ VARIANT_ENUM_CAST( wchar_t ); VARIANT_ENUM_CAST( Margin ); VARIANT_ENUM_CAST( Orientation ); VARIANT_ENUM_CAST( HAlign ); +VARIANT_ENUM_CAST( Variant::Type ); +VARIANT_ENUM_CAST( Variant::Operator ); class MethodBind { @@ -170,11 +172,13 @@ class MethodBind { StringName ret_type; #endif bool _const; + bool _returns; protected: void _set_const(bool p_const); + void _set_returns(bool p_returns); #ifdef DEBUG_METHODS_ENABLED virtual Variant::Type _gen_argument_type(int p_arg) const=0; void _generate_argument_types(int p_count); @@ -261,6 +265,7 @@ public: void set_name(const StringName& p_name); _FORCE_INLINE_ int get_method_id() const { return method_id; } _FORCE_INLINE_ bool is_const() const { return _const; } + _FORCE_INLINE_ bool has_return() const { return _returns; } void set_default_arguments(const Vector& p_defargs); @@ -321,7 +326,7 @@ public: virtual bool is_const() const { return false; } virtual String get_instance_type() const { return T::get_type_static(); } - MethodBindNative() { call_method=NULL; } + MethodBindNative() { call_method=NULL; _set_returns(true);} }; diff --git a/core/object.h b/core/object.h index d7b0f09df99..400ab3070ed 100644 --- a/core/object.h +++ b/core/object.h @@ -68,6 +68,8 @@ enum PropertyHint { PROPERTY_HINT_IMAGE_COMPRESS_LOSSY, PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS, PROPERTY_HINT_OBJECT_ID, + PROPERTY_HINT_TYPE_STRING, ///< a type string, the hint is the base type to choose + PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE, ///< so something else can provide this (used in scripts) PROPERTY_HINT_MAX, }; diff --git a/core/script_language.h b/core/script_language.h index 6d75b83aaf4..499dbe14a7d 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -110,6 +110,7 @@ public: virtual bool get_property_default_value(const StringName& p_property,Variant& r_value) const=0; virtual void update_exports() {} //editor tool + virtual void get_method_list(List *p_list) const=0; Script() {} diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index d1946e2a632..cc46d91a2d7 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -249,6 +249,23 @@ void GDScript::_update_placeholder(PlaceHolderScriptInstance *p_placeholder) { }*/ #endif + +void GDScript::get_method_list(List *p_list) const { + + for (const Map::Element *E=member_functions.front();E;E=E->next()) { + MethodInfo mi; + mi.name=E->key(); + for(int i=0;iget()->get_argument_count();i++) { + PropertyInfo arg; + arg.type=Variant::NIL; //variant + arg.name=E->get()->get_argument_name(i); + mi.arguments.push_back(arg); + } + + mi.return_val.name="var"; + p_list->push_back(mi); + } +} bool GDScript::get_property_default_value(const StringName& p_property, Variant &r_value) const { #ifdef TOOLS_ENABLED diff --git a/modules/gdscript/gd_script.h b/modules/gdscript/gd_script.h index f0b6b7103c2..41c5c32e499 100644 --- a/modules/gdscript/gd_script.h +++ b/modules/gdscript/gd_script.h @@ -181,6 +181,8 @@ public: bool get_property_default_value(const StringName& p_property,Variant& r_value) const; + virtual void get_method_list(List *p_list) const; + virtual ScriptLanguage *get_language() const; GDScript(); diff --git a/modules/visual_script/SCsub b/modules/visual_script/SCsub new file mode 100644 index 00000000000..403fe68f662 --- /dev/null +++ b/modules/visual_script/SCsub @@ -0,0 +1,5 @@ +Import('env') + +env.add_source_files(env.modules_sources,"*.cpp") + +Export('env') diff --git a/modules/visual_script/config.py b/modules/visual_script/config.py new file mode 100644 index 00000000000..ea7e83378a9 --- /dev/null +++ b/modules/visual_script/config.py @@ -0,0 +1,11 @@ + + +def can_build(platform): + return True + + +def configure(env): + pass + + + diff --git a/modules/visual_script/register_types.cpp b/modules/visual_script/register_types.cpp new file mode 100644 index 00000000000..2cd84203e86 --- /dev/null +++ b/modules/visual_script/register_types.cpp @@ -0,0 +1,96 @@ +/*************************************************************************/ +/* register_types.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "register_types.h" + +#include "visual_script.h" +#include "visual_script_editor.h" +#include "io/resource_loader.h" +#include "visual_script_nodes.h" +#include "visual_script_func_nodes.h" +#include "visual_script_builtin_funcs.h" +#include "visual_script_flow_control.h" + + +VisualScriptLanguage *visual_script_language=NULL; + + +void register_visual_script_types() { + + ObjectTypeDB::register_type(); + ObjectTypeDB::register_virtual_type(); + ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); + + ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); + + ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); + + ObjectTypeDB::register_type(); + + visual_script_language=memnew( VisualScriptLanguage ); + //script_language_gd->init(); + ScriptServer::register_language(visual_script_language); + + register_visual_script_nodes(); + register_visual_script_func_nodes(); + register_visual_script_builtin_func_node(); + register_visual_script_flow_control_nodes(); + +#ifdef TOOLS_ENABLED + VisualScriptEditor::register_editor(); +#endif + + +} + +void unregister_visual_script_types() { + + + ScriptServer::unregister_language(visual_script_language); + + if (visual_script_language) + memdelete( visual_script_language ); + +} diff --git a/modules/visual_script/register_types.h b/modules/visual_script/register_types.h new file mode 100644 index 00000000000..0a5805eb0b4 --- /dev/null +++ b/modules/visual_script/register_types.h @@ -0,0 +1,30 @@ +/*************************************************************************/ +/* register_types.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +void register_visual_script_types(); +void unregister_visual_script_types(); diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp new file mode 100644 index 00000000000..6541ac6b861 --- /dev/null +++ b/modules/visual_script/visual_script.cpp @@ -0,0 +1,1156 @@ +#include "visual_script.h" +#include "visual_script_nodes.h" + +void VisualScriptNode::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("get_visual_script:VisualScript"),&VisualScriptNode::get_visual_script); + ADD_SIGNAL(MethodInfo("ports_changed")); +} + + +Ref VisualScriptNode::get_visual_script() const { + + if (scripts_used.size()) + return Ref(scripts_used.front()->get()); + + return Ref(); + +} + +//////////////// + +///////////////////// + +VisualScriptNodeInstance::~VisualScriptNodeInstance() { + +} + +void VisualScript::add_function(const StringName& p_name) { + + ERR_FAIL_COND(!String(p_name).is_valid_identifier()); + ERR_FAIL_COND(functions.has(p_name)); + + functions[p_name]=Function(); +} + +bool VisualScript::has_function(const StringName& p_name) const { + + return functions.has(p_name); + +} +void VisualScript::remove_function(const StringName& p_name) { + + ERR_FAIL_COND(!functions.has(p_name)); + + for (Map::Element *E=functions[p_name].nodes.front();E;E=E->next()) { + + E->get().node->disconnect("ports_changed",this,"_node_ports_changed"); + E->get().node->scripts_used.erase(this); + } + + functions.erase(p_name); + +} + +void VisualScript::rename_function(const StringName& p_name,const StringName& p_new_name) { + + ERR_FAIL_COND(!functions.has(p_name)); + if (p_new_name==p_name) + return; + + ERR_FAIL_COND(!String(p_new_name).is_valid_identifier()); + + ERR_FAIL_COND(functions.has(p_new_name)); + ERR_FAIL_COND(variables.has(p_new_name)); + ERR_FAIL_COND(custom_signals.has(p_new_name)); + + functions[p_new_name]=functions[p_name]; + functions.erase(p_name); + +} + +void VisualScript::get_function_list(List *r_functions) const { + + for (const Map::Element *E=functions.front();E;E=E->next()) { + r_functions->push_back(E->key()); + } + + r_functions->sort_custom(); + +} + +int VisualScript::get_function_node_id(const StringName& p_name) const { + + ERR_FAIL_COND_V(!functions.has(p_name),-1); + + return functions[p_name].function_id; + +} + + +void VisualScript::_node_ports_changed(int p_id) { + + + StringName function; + + for (Map::Element *E=functions.front();E;E=E->next()) { + + if (E->get().nodes.has(p_id)) { + function=E->key(); + break; + } + } + + ERR_FAIL_COND(function==StringName()); + + Function &func = functions[function]; + Ref vsn = func.nodes[p_id].node; + + //must revalidate all the functions + + { + List to_remove; + + for (Set::Element *E=func.sequence_connections.front();E;E=E->next()) { + if (E->get().from_node==p_id && E->get().from_output>=vsn->get_output_sequence_port_count()) { + + to_remove.push_back(E->get()); + } + if (E->get().to_node==p_id && !vsn->has_input_sequence_port()) { + + to_remove.push_back(E->get()); + } + } + + while(to_remove.size()) { + func.sequence_connections.erase(to_remove.front()->get()); + to_remove.pop_front(); + } + } + + { + + List to_remove; + + + for (Set::Element *E=func.data_connections.front();E;E=E->next()) { + if (E->get().from_node==p_id && E->get().from_port>=vsn->get_output_value_port_count()) { + to_remove.push_back(E->get()); + } + if (E->get().to_node==p_id && E->get().to_port>=vsn->get_input_value_port_count()) { + to_remove.push_back(E->get()); + } + } + + while(to_remove.size()) { + func.data_connections.erase(to_remove.front()->get()); + to_remove.pop_front(); + } + } + + emit_signal("node_ports_changed",function,p_id); +} + +void VisualScript::add_node(const StringName& p_func,int p_id, const Ref& p_node, const Point2 &p_pos) { + + ERR_FAIL_COND(!functions.has(p_func)); + + + for (Map::Element *E=functions.front();E;E=E->next()) { + + ERR_FAIL_COND(E->get().nodes.has(p_id)); //id can exist only one in script, even for different functions + } + + Function &func = functions[p_func]; + + + if (p_node->cast_to()) { + //the function indeed + ERR_EXPLAIN("A function node already has been set here."); + ERR_FAIL_COND(func.function_id>=0); + + func.function_id=p_id; + } + + Function::NodeData nd; + nd.node=p_node; + nd.pos=p_pos; + + Ref vsn = p_node; + vsn->connect("ports_changed",this,"_node_ports_changed",varray(p_id)); + vsn->scripts_used.insert(this); + + + + func.nodes[p_id]=nd; +} + +void VisualScript::remove_node(const StringName& p_func,int p_id){ + + ERR_FAIL_COND(!functions.has(p_func)); + Function &func = functions[p_func]; + + ERR_FAIL_COND(!func.nodes.has(p_id)); + { + List to_remove; + + for (Set::Element *E=func.sequence_connections.front();E;E=E->next()) { + if (E->get().from_node==p_id || E->get().to_node==p_id) { + to_remove.push_back(E->get()); + } + } + + while(to_remove.size()) { + func.sequence_connections.erase(to_remove.front()->get()); + to_remove.pop_front(); + } + } + + { + + List to_remove; + + + for (Set::Element *E=func.data_connections.front();E;E=E->next()) { + if (E->get().from_node==p_id || E->get().to_node==p_id) { + to_remove.push_back(E->get()); + } + } + + while(to_remove.size()) { + func.data_connections.erase(to_remove.front()->get()); + to_remove.pop_front(); + } + } + + if (func.nodes[p_id].node->cast_to()) { + func.function_id=-1; //revert to invalid + } + + func.nodes[p_id].node->disconnect("ports_changed",this,"_node_ports_changed"); + func.nodes[p_id].node->scripts_used.erase(this); + + func.nodes.erase(p_id); + + +} + + + +Ref VisualScript::get_node(const StringName& p_func,int p_id) const{ + + ERR_FAIL_COND_V(!functions.has(p_func),Ref()); + const Function &func = functions[p_func]; + + ERR_FAIL_COND_V(!func.nodes.has(p_id),Ref()); + + return func.nodes[p_id].node; +} + +void VisualScript::set_node_pos(const StringName& p_func,int p_id,const Point2& p_pos) { + + ERR_FAIL_COND(!functions.has(p_func)); + Function &func = functions[p_func]; + + ERR_FAIL_COND(!func.nodes.has(p_id)); + func.nodes[p_id].pos=p_pos; +} + +Point2 VisualScript::get_node_pos(const StringName& p_func,int p_id) const{ + + ERR_FAIL_COND_V(!functions.has(p_func),Point2()); + const Function &func = functions[p_func]; + + ERR_FAIL_COND_V(!func.nodes.has(p_id),Point2()); + return func.nodes[p_id].pos; +} + + +void VisualScript::get_node_list(const StringName& p_func,List *r_nodes) const{ + + ERR_FAIL_COND(!functions.has(p_func)); + const Function &func = functions[p_func]; + + for (const Map::Element *E=func.nodes.front();E;E=E->next()) { + r_nodes->push_back(E->key()); + } + +} + + +void VisualScript::sequence_connect(const StringName& p_func,int p_from_node,int p_from_output,int p_to_node){ + + ERR_FAIL_COND(!functions.has(p_func)); + Function &func = functions[p_func]; + + + SequenceConnection sc; + sc.from_node=p_from_node; + sc.from_output=p_from_output; + sc.to_node=p_to_node; + ERR_FAIL_COND(func.sequence_connections.has(sc)); + + func.sequence_connections.insert(sc); + +} + +void VisualScript::sequence_disconnect(const StringName& p_func,int p_from_node,int p_from_output,int p_to_node){ + + ERR_FAIL_COND(!functions.has(p_func)); + Function &func = functions[p_func]; + + SequenceConnection sc; + sc.from_node=p_from_node; + sc.from_output=p_from_output; + sc.to_node=p_to_node; + ERR_FAIL_COND(!func.sequence_connections.has(sc)); + + func.sequence_connections.erase(sc); + +} + +bool VisualScript::has_sequence_connection(const StringName& p_func,int p_from_node,int p_from_output,int p_to_node) const{ + + ERR_FAIL_COND_V(!functions.has(p_func),false); + const Function &func = functions[p_func]; + + SequenceConnection sc; + sc.from_node=p_from_node; + sc.from_output=p_from_output; + sc.to_node=p_to_node; + + return func.sequence_connections.has(sc); +} + +void VisualScript::get_sequence_connection_list(const StringName& p_func,List *r_connection) const { + + ERR_FAIL_COND(!functions.has(p_func)); + const Function &func = functions[p_func]; + + for (const Set::Element *E=func.sequence_connections.front();E;E=E->next()) { + r_connection->push_back(E->get()); + } +} + + +void VisualScript::data_connect(const StringName& p_func,int p_from_node,int p_from_port,int p_to_node,int p_to_port) { + + ERR_FAIL_COND(!functions.has(p_func)); + Function &func = functions[p_func]; + + DataConnection dc; + dc.from_node=p_from_node; + dc.from_port=p_from_port; + dc.to_node=p_to_node; + dc.to_port=p_to_port; + + ERR_FAIL_COND( func.data_connections.has(dc)); + + func.data_connections.insert(dc); +} + +void VisualScript::data_disconnect(const StringName& p_func,int p_from_node,int p_from_port,int p_to_node,int p_to_port) { + + ERR_FAIL_COND(!functions.has(p_func)); + Function &func = functions[p_func]; + + DataConnection dc; + dc.from_node=p_from_node; + dc.from_port=p_from_port; + dc.to_node=p_to_node; + dc.to_port=p_to_port; + + ERR_FAIL_COND( !func.data_connections.has(dc)); + + func.data_connections.erase(dc); + +} + +bool VisualScript::has_data_connection(const StringName& p_func,int p_from_node,int p_from_port,int p_to_node,int p_to_port) const { + + ERR_FAIL_COND_V(!functions.has(p_func),false); + const Function &func = functions[p_func]; + + DataConnection dc; + dc.from_node=p_from_node; + dc.from_port=p_from_port; + dc.to_node=p_to_node; + dc.to_port=p_to_port; + + return func.data_connections.has(dc); + +} + +void VisualScript::get_data_connection_list(const StringName& p_func,List *r_connection) const { + + ERR_FAIL_COND(!functions.has(p_func)); + const Function &func = functions[p_func]; + + for (const Set::Element *E=func.data_connections.front();E;E=E->next()) { + r_connection->push_back(E->get()); + } +} + +void VisualScript::add_variable(const StringName& p_name,const Variant& p_default_value) { + + ERR_FAIL_COND(!String(p_name).is_valid_identifier()); + ERR_FAIL_COND(variables.has(p_name)); + + Variable v; + v.default_value=p_default_value; + v.info.type=p_default_value.get_type(); + v.info.name=p_name; + v.info.hint=PROPERTY_HINT_NONE; + + variables[p_name]=v; + +} + +bool VisualScript::has_variable(const StringName& p_name) const { + + return variables.has(p_name); +} + +void VisualScript::remove_variable(const StringName& p_name) { + + ERR_FAIL_COND(!variables.has(p_name)); + variables.erase(p_name); +} + +void VisualScript::set_variable_default_value(const StringName& p_name,const Variant& p_value){ + + ERR_FAIL_COND(!variables.has(p_name)); + + variables[p_name].default_value=p_value; + +} +Variant VisualScript::get_variable_default_value(const StringName& p_name) const{ + + ERR_FAIL_COND_V(!variables.has(p_name),Variant()); + return variables[p_name].default_value; + +} +void VisualScript::set_variable_info(const StringName& p_name,const PropertyInfo& p_info){ + + ERR_FAIL_COND(!variables.has(p_name)); + variables[p_name].info=p_info; + variables[p_name].info.name=p_name; + + +} +PropertyInfo VisualScript::get_variable_info(const StringName& p_name) const{ + + ERR_FAIL_COND_V(!variables.has(p_name),PropertyInfo()); + return variables[p_name].info; +} + +void VisualScript::_set_variable_info(const StringName& p_name,const Dictionary& p_info) { + + PropertyInfo pinfo; + if (p_info.has("type")) + pinfo.type=Variant::Type(int(p_info["type"])); + if (p_info.has("name")) + pinfo.name=p_info["name"]; + if (p_info.has("hint")) + pinfo.hint=PropertyHint(int(p_info["hint"])); + if (p_info.has("hint_string")) + pinfo.hint_string=p_info["hint_string"]; + if (p_info.has("usage")) + pinfo.usage=p_info["usage"]; + + set_variable_info(p_name,pinfo); +} + +Dictionary VisualScript::_get_variable_info(const StringName& p_name) const{ + + PropertyInfo pinfo=get_variable_info(p_name); + Dictionary d; + d["type"]=pinfo.type; + d["name"]=pinfo.name; + d["hint"]=pinfo.hint; + d["hint_string"]=pinfo.hint_string; + d["usage"]=pinfo.usage; + + return d; +} + +void VisualScript::get_variable_list(List *r_variables){ + + + for (Map::Element *E=variables.front();E;E=E->next()) { + r_variables->push_back(E->key()); + } + + r_variables->sort_custom(); +} + + +void VisualScript::set_instance_base_type(const StringName& p_type) { + + base_type=p_type; +} + + +void VisualScript::rename_variable(const StringName& p_name,const StringName& p_new_name) { + + ERR_FAIL_COND(!variables.has(p_name)); + if (p_new_name==p_name) + return; + + ERR_FAIL_COND(!String(p_new_name).is_valid_identifier()); + + ERR_FAIL_COND(functions.has(p_new_name)); + ERR_FAIL_COND(variables.has(p_new_name)); + ERR_FAIL_COND(custom_signals.has(p_new_name)); + + variables[p_new_name]=variables[p_name]; + variables.erase(p_name); + +} + +void VisualScript::add_custom_signal(const StringName& p_name) { + + ERR_FAIL_COND(!String(p_name).is_valid_identifier()); + ERR_FAIL_COND(custom_signals.has(p_name)); + + custom_signals[p_name]=Vector(); +} + +bool VisualScript::has_custom_signal(const StringName& p_name) const { + + return custom_signals.has(p_name); + +} +void VisualScript::custom_signal_add_argument(const StringName& p_func,Variant::Type p_type,const String& p_name,int p_index) { + + ERR_FAIL_COND(!custom_signals.has(p_func)); + Argument arg; + arg.type=p_type; + arg.name=p_name; + if (p_index<0) + custom_signals[p_func].push_back(arg); + else + custom_signals[p_func].insert(0,arg); + +} +void VisualScript::custom_signal_set_argument_type(const StringName& p_func,int p_argidx,Variant::Type p_type) { + + ERR_FAIL_COND(!custom_signals.has(p_func)); + ERR_FAIL_INDEX(p_argidx,custom_signals[p_func].size()); + custom_signals[p_func][p_argidx].type=p_type; +} +Variant::Type VisualScript::custom_signal_get_argument_type(const StringName& p_func,int p_argidx) const { + + ERR_FAIL_COND_V(!custom_signals.has(p_func),Variant::NIL); + ERR_FAIL_INDEX_V(p_argidx,custom_signals[p_func].size(),Variant::NIL); + return custom_signals[p_func][p_argidx].type; +} +void VisualScript::custom_signal_set_argument_name(const StringName& p_func,int p_argidx,const String& p_name) { + ERR_FAIL_COND(!custom_signals.has(p_func)); + ERR_FAIL_INDEX(p_argidx,custom_signals[p_func].size()); + custom_signals[p_func][p_argidx].name=p_name; + +} +String VisualScript::custom_signal_get_argument_name(const StringName& p_func,int p_argidx) const { + + ERR_FAIL_COND_V(!custom_signals.has(p_func),String()); + ERR_FAIL_INDEX_V(p_argidx,custom_signals[p_func].size(),String()); + return custom_signals[p_func][p_argidx].name; + +} +void VisualScript::custom_signal_remove_argument(const StringName& p_func,int p_argidx) { + + ERR_FAIL_COND(!custom_signals.has(p_func)); + ERR_FAIL_INDEX(p_argidx,custom_signals[p_func].size()); + custom_signals[p_func].remove(p_argidx); + +} + +int VisualScript::custom_signal_get_argument_count(const StringName& p_func) const { + + ERR_FAIL_COND_V(!custom_signals.has(p_func),0); + return custom_signals[p_func].size(); + +} +void VisualScript::custom_signal_swap_argument(const StringName& p_func,int p_argidx,int p_with_argidx) { + + ERR_FAIL_COND(!custom_signals.has(p_func)); + ERR_FAIL_INDEX(p_argidx,custom_signals[p_func].size()); + ERR_FAIL_INDEX(p_with_argidx,custom_signals[p_func].size()); + + SWAP( custom_signals[p_func][p_argidx], custom_signals[p_func][p_with_argidx] ); + +} +void VisualScript::remove_custom_signal(const StringName& p_name) { + + ERR_FAIL_COND(!custom_signals.has(p_name)); + custom_signals.erase(p_name); + +} + +void VisualScript::rename_custom_signal(const StringName& p_name,const StringName& p_new_name) { + + ERR_FAIL_COND(!custom_signals.has(p_name)); + if (p_new_name==p_name) + return; + + ERR_FAIL_COND(!String(p_new_name).is_valid_identifier()); + + ERR_FAIL_COND(functions.has(p_new_name)); + ERR_FAIL_COND(variables.has(p_new_name)); + ERR_FAIL_COND(custom_signals.has(p_new_name)); + + custom_signals[p_new_name]=custom_signals[p_name]; + custom_signals.erase(p_name); + +} + +void VisualScript::get_custom_signal_list(List *r_custom_signals) const { + + for (const Map >::Element *E=custom_signals.front();E;E=E->next()) { + r_custom_signals->push_back(E->key()); + } + + r_custom_signals->sort_custom(); + +} + +int VisualScript::get_available_id() const { + + int max_id=0; + for (Map::Element *E=functions.front();E;E=E->next()) { + if (E->get().nodes.empty()) + continue; + + int last_id = E->get().nodes.back()->key(); + max_id=MAX(max_id,last_id+1); + } + + return max_id; +} + +///////////////////////////////// + + +bool VisualScript::can_instance() const { + + return ScriptServer::is_scripting_enabled(); + +} + + +StringName VisualScript::get_instance_base_type() const { + + return base_type; +} + +ScriptInstance* VisualScript::instance_create(Object *p_this) { + + return NULL; +} + +bool VisualScript::instance_has(const Object *p_this) const { + + return false; +} + +bool VisualScript::has_source_code() const { + + return false; +} + +String VisualScript::get_source_code() const { + + return String(); +} + +void VisualScript::set_source_code(const String& p_code) { + +} + +Error VisualScript::reload(bool p_keep_state) { + + return OK; +} + + +bool VisualScript::is_tool() const { + + return false; +} + + +String VisualScript::get_node_type() const { + + return String(); +} + + +ScriptLanguage *VisualScript::get_language() const { + + return VisualScriptLanguage::singleton; +} + + +bool VisualScript::has_script_signal(const StringName& p_signal) const { + + return false; +} + +void VisualScript::get_script_signal_list(List *r_signals) const { + +} + + +bool VisualScript::get_property_default_value(const StringName& p_property,Variant& r_value) const { + + return false; +} +void VisualScript::get_method_list(List *p_list) const { + + for (Map::Element *E=functions.front();E;E=E->next()) { + + MethodInfo mi; + mi.name=E->key(); + if (E->get().function_id>=0) { + + Ref func=E->get().nodes[E->get().function_id].node; + if (func.is_valid()) { + + for(int i=0;iget_argument_count();i++) { + PropertyInfo arg; + arg.name=func->get_argument_name(i); + arg.type=func->get_argument_type(i); + mi.arguments.push_back(arg); + } + } + } + + p_list->push_back(mi); + } +} + +void VisualScript::_set_data(const Dictionary& p_data) { + + Dictionary d = p_data; + if (d.has("base_type")) + base_type=d["base_type"]; + + variables.clear(); + Array vars=d["variables"]; + for (int i=0;i::Element *E=variables.front();E;E=E->next()) { + + 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; + vars.push_back(var); + } + d["variables"]=vars; + + Array sigs; + for (const Map >::Element *E=custom_signals.front();E;E=E->next()) { + + Dictionary cs; + cs["name"]=E->key(); + Array args; + for(int i=0;iget().size();i++) { + args.push_back(E->get()[i].name); + args.push_back(E->get()[i].type); + } + cs["arguments"]=args; + + sigs.push_back(cs); + } + + d["signals"]=sigs; + + Array funcs; + + for (const Map::Element *E=functions.front();E;E=E->next()) { + + Dictionary func; + func["name"]=E->key(); + func["function_id"]=E->get().function_id; + + Array nodes; + + for (const Map::Element *F=E->get().nodes.front();F;F=F->next()) { + + nodes.push_back(F->key()); + nodes.push_back(F->get().pos); + nodes.push_back(F->get().node); + + } + + func["nodes"]=nodes; + + Array sequence_connections; + + for (const Set::Element *F=E->get().sequence_connections.front();F;F=F->next()) { + + sequence_connections.push_back(F->get().from_node); + sequence_connections.push_back(F->get().from_output); + sequence_connections.push_back(F->get().to_node); + + } + + + func["sequence_connections"]=sequence_connections; + + Array data_connections; + + for (const Set::Element *F=E->get().data_connections.front();F;F=F->next()) { + + data_connections.push_back(F->get().from_node); + data_connections.push_back(F->get().from_port); + data_connections.push_back(F->get().to_node); + data_connections.push_back(F->get().to_port); + + } + + + func["data_connections"]=data_connections; + + funcs.push_back(func); + + } + + d["functions"]=funcs; + + + return d; + +} + +void VisualScript::_bind_methods() { + + + + ObjectTypeDB::bind_method(_MD("_node_ports_changed"),&VisualScript::_node_ports_changed); + + ObjectTypeDB::bind_method(_MD("add_function","name"),&VisualScript::add_function); + ObjectTypeDB::bind_method(_MD("has_function","name"),&VisualScript::has_function); + ObjectTypeDB::bind_method(_MD("remove_function","name"),&VisualScript::remove_function); + ObjectTypeDB::bind_method(_MD("rename_function","name","new_name"),&VisualScript::rename_function); + + ObjectTypeDB::bind_method(_MD("add_node","func","id","node","pos"),&VisualScript::add_node,DEFVAL(Point2())); + ObjectTypeDB::bind_method(_MD("remove_node","func","id"),&VisualScript::remove_node); + ObjectTypeDB::bind_method(_MD("get_function_node_id","name"),&VisualScript::get_function_node_id); + + ObjectTypeDB::bind_method(_MD("get_node","func","id"),&VisualScript::get_node); + ObjectTypeDB::bind_method(_MD("set_node_pos","func","id","pos"),&VisualScript::set_node_pos); + ObjectTypeDB::bind_method(_MD("get_node_pos","func","id"),&VisualScript::get_node_pos); + + ObjectTypeDB::bind_method(_MD("sequence_connect","func","from_node","from_output","to_node"),&VisualScript::sequence_connect); + ObjectTypeDB::bind_method(_MD("sequence_disconnect","func","from_node","from_output","to_node"),&VisualScript::sequence_disconnect); + ObjectTypeDB::bind_method(_MD("has_sequence_connection","func","from_node","from_output","to_node"),&VisualScript::has_sequence_connection); + + ObjectTypeDB::bind_method(_MD("data_connect","func","from_node","from_port","to_node","to_port"),&VisualScript::data_connect); + 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("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("rename_variable","name","new_name"),&VisualScript::rename_variable); + + ObjectTypeDB::bind_method(_MD("add_custom_signal","name"),&VisualScript::add_custom_signal); + ObjectTypeDB::bind_method(_MD("has_custom_signal","name"),&VisualScript::has_custom_signal); + ObjectTypeDB::bind_method(_MD("custom_signal_add_argument","name","type","argname","index"),&VisualScript::custom_signal_add_argument,DEFVAL(-1)); + ObjectTypeDB::bind_method(_MD("custom_signal_set_argument_type","name","argidx","type"),&VisualScript::custom_signal_set_argument_type); + ObjectTypeDB::bind_method(_MD("custom_signal_get_argument_type","name","argidx"),&VisualScript::custom_signal_get_argument_type); + ObjectTypeDB::bind_method(_MD("custom_signal_set_argument_name","name","argidx","argname"),&VisualScript::custom_signal_set_argument_name); + ObjectTypeDB::bind_method(_MD("custom_signal_get_argument_name","name","argidx"),&VisualScript::custom_signal_get_argument_name); + ObjectTypeDB::bind_method(_MD("custom_signal_remove_argument","argidx"),&VisualScript::custom_signal_remove_argument); + ObjectTypeDB::bind_method(_MD("custom_signal_get_argument_count","name"),&VisualScript::custom_signal_get_argument_count); + ObjectTypeDB::bind_method(_MD("custom_signal_swap_argument","name","argidx","withidx"),&VisualScript::custom_signal_swap_argument); + ObjectTypeDB::bind_method(_MD("remove_custom_signal","name"),&VisualScript::remove_custom_signal); + ObjectTypeDB::bind_method(_MD("rename_custom_signal","name","new_name"),&VisualScript::rename_custom_signal); + + //ObjectTypeDB::bind_method(_MD("set_variable_info","name","info"),&VScript::set_variable_info); + //ObjectTypeDB::bind_method(_MD("get_variable_info","name"),&VScript::set_variable_info); + + ObjectTypeDB::bind_method(_MD("set_instance_base_type","type"),&VisualScript::set_instance_base_type); + + ObjectTypeDB::bind_method(_MD("_set_data","data"),&VisualScript::_set_data); + ObjectTypeDB::bind_method(_MD("_get_data"),&VisualScript::_get_data); + + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY,"data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_data"),_SCS("_get_data")); + + ADD_SIGNAL(MethodInfo("node_ports_changed",PropertyInfo(Variant::STRING,"function"),PropertyInfo(Variant::INT,"id"))); +} + +VisualScript::VisualScript() { + + base_type="Object"; + +} + +VisualScript::~VisualScript() { + + while(!functions.empty()) { + remove_function(functions.front()->key()); + } + +} + +//////////////////////////////////////////// + + +String VisualScriptLanguage::get_name() const { + + return "VisualScript"; +} + +/* LANGUAGE FUNCTIONS */ +void VisualScriptLanguage::init() { + + +} +String VisualScriptLanguage::get_type() const { + + return "VisualScript"; +} +String VisualScriptLanguage::get_extension() const { + + return "vs"; +} +Error VisualScriptLanguage::execute_file(const String& p_path) { + + return OK; +} +void VisualScriptLanguage::finish() { + + +} + +/* EDITOR FUNCTIONS */ +void VisualScriptLanguage::get_reserved_words(List *p_words) const { + + +} +void VisualScriptLanguage::get_comment_delimiters(List *p_delimiters) const { + + +} +void VisualScriptLanguage::get_string_delimiters(List *p_delimiters) const { + + +} +String VisualScriptLanguage::get_template(const String& p_class_name, const String& p_base_class_name) const { + + return String(); +} +bool VisualScriptLanguage::validate(const String& p_script, int &r_line_error,int &r_col_error,String& r_test_error, const String& p_path,List *r_functions) const { + + return false; +} +Script *VisualScriptLanguage::create_script() const { + + return memnew( VisualScript ); +} +bool VisualScriptLanguage::has_named_classes() const { + + return false; +} +int VisualScriptLanguage::find_function(const String& p_function,const String& p_code) const { + + return -1; +} +String VisualScriptLanguage::make_function(const String& p_class,const String& p_name,const StringArray& p_args) const { + + return String(); +} + +void VisualScriptLanguage::auto_indent_code(String& p_code,int p_from_line,int p_to_line) const { + + +} +void VisualScriptLanguage::add_global_constant(const StringName& p_variable,const Variant& p_value) { + + +} + + +/* DEBUGGER FUNCTIONS */ + +String VisualScriptLanguage::debug_get_error() const { + + return String(); +} +int VisualScriptLanguage::debug_get_stack_level_count() const { + + return 0; +} +int VisualScriptLanguage::debug_get_stack_level_line(int p_level) const { + + return 0; +} +String VisualScriptLanguage::debug_get_stack_level_function(int p_level) const { + + return String(); +} +String VisualScriptLanguage::debug_get_stack_level_source(int p_level) const { + + return String(); +} +void VisualScriptLanguage::debug_get_stack_level_locals(int p_level,List *p_locals, List *p_values, int p_max_subitems,int p_max_depth) { + + +} +void VisualScriptLanguage::debug_get_stack_level_members(int p_level,List *p_members, List *p_values, int p_max_subitems,int p_max_depth) { + + +} +void VisualScriptLanguage::debug_get_globals(List *p_locals, List *p_values, int p_max_subitems,int p_max_depth) { + + +} +String VisualScriptLanguage::debug_parse_stack_level_expression(int p_level,const String& p_expression,int p_max_subitems,int p_max_depth) { + + return String(); +} + + +void VisualScriptLanguage::reload_all_scripts() { + + +} +void VisualScriptLanguage::reload_tool_script(const Ref