diff options
Diffstat (limited to 'scene/main')
-rw-r--r-- | scene/main/http_request.cpp | 12 | ||||
-rw-r--r-- | scene/main/http_request.h | 4 | ||||
-rw-r--r-- | scene/main/node.cpp | 717 | ||||
-rw-r--r-- | scene/main/node.h | 60 | ||||
-rw-r--r-- | scene/main/scene_main_loop.cpp | 576 | ||||
-rw-r--r-- | scene/main/scene_main_loop.h | 84 | ||||
-rw-r--r-- | scene/main/viewport.cpp | 1 |
7 files changed, 1441 insertions, 13 deletions
diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index 9b79af32bf..c713b5e4dc 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -96,7 +96,7 @@ Error HTTPRequest::_parse_url(const String& p_url) { return OK; } -Error HTTPRequest::request(const String& p_url, const Vector<String>& p_custom_headers, bool p_ssl_validate_domain) { +Error HTTPRequest::request(const String& p_url, const Vector<String>& p_custom_headers, bool p_ssl_validate_domain, HTTPClient::Method p_method, const String& p_request_data) { ERR_FAIL_COND_V(!is_inside_tree(),ERR_UNCONFIGURED); if ( requesting ) { @@ -104,6 +104,8 @@ Error HTTPRequest::request(const String& p_url, const Vector<String>& p_custom_h ERR_FAIL_V(ERR_BUSY); } + method=p_method; + Error err = _parse_url(p_url); if (err) return err; @@ -114,6 +116,8 @@ Error HTTPRequest::request(const String& p_url, const Vector<String>& p_custom_h bool has_accept=false; headers=p_custom_headers; + request_data = p_request_data; + for(int i=0;i<headers.size();i++) { if (headers[i].findn("user-agent:")==0) @@ -281,7 +285,7 @@ bool HTTPRequest::_update_connection() { switch( client->get_status() ) { case HTTPClient::STATUS_DISCONNECTED: { call_deferred("_request_done",RESULT_CANT_CONNECT,0,StringArray(),ByteArray()); - return true; //end it, since it's doing something + return true; //end it, since it's doing something } break; case HTTPClient::STATUS_RESOLVING: { client->poll(); @@ -334,7 +338,7 @@ bool HTTPRequest::_update_connection() { } else { //did not request yet, do request - Error err = client->request(HTTPClient::METHOD_GET,request_string,headers); + Error err = client->request(method,request_string,headers,request_data); if (err!=OK) { call_deferred("_request_done",RESULT_CONNECTION_ERROR,0,StringArray(),ByteArray()); return true; @@ -531,7 +535,7 @@ int HTTPRequest::get_body_size() const{ void HTTPRequest::_bind_methods() { - ObjectTypeDB::bind_method(_MD("request","url","custom_headers","ssl_validate_domain"),&HTTPRequest::request,DEFVAL(StringArray()),DEFVAL(true)); + ObjectTypeDB::bind_method(_MD("request","url","custom_headers","ssl_validate_domain","method","request_data"),&HTTPRequest::request,DEFVAL(StringArray()),DEFVAL(true),DEFVAL(HTTPClient::METHOD_GET),DEFVAL(String())); ObjectTypeDB::bind_method(_MD("cancel_request"),&HTTPRequest::cancel_request); ObjectTypeDB::bind_method(_MD("get_http_client_status"),&HTTPRequest::get_http_client_status); diff --git a/scene/main/http_request.h b/scene/main/http_request.h index 8dd433982b..705799f044 100644 --- a/scene/main/http_request.h +++ b/scene/main/http_request.h @@ -66,6 +66,8 @@ private: Vector<String> headers; bool validate_ssl; bool use_ssl; + HTTPClient::Method method; + String request_data; bool request_sent; Ref<HTTPClient> client; @@ -114,7 +116,7 @@ protected: static void _bind_methods(); public: - Error request(const String& p_url,const Vector<String>& p_custom_headers=Vector<String>(),bool p_ssl_validate_domain=true); //connects to a full url and perform request + Error request(const String& p_url, const Vector<String>& p_custom_headers=Vector<String>(), bool p_ssl_validate_domain=true, HTTPClient::Method p_method=HTTPClient::METHOD_GET, const String& p_request_data=""); //connects to a full url and perform request void cancel_request(); HTTPClient::Status get_http_client_status() const; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index a53c19d2e7..1892240426 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -36,6 +36,8 @@ #include "instance_placeholder.h" VARIANT_ENUM_CAST(Node::PauseMode); +VARIANT_ENUM_CAST(Node::NetworkMode); +VARIANT_ENUM_CAST(Node::RPCMode); @@ -77,6 +79,16 @@ void Node::_notification(int p_notification) { data.pause_owner=this; } + if (data.network_mode==NETWORK_MODE_INHERIT) { + + if (data.parent) + data.network_owner=data.parent->data.network_owner; + else + data.network_owner=NULL; + } else { + data.network_owner=this; + } + if (data.input) add_to_group("_vp_input"+itos(get_viewport()->get_instance_ID())); if (data.unhandled_input) @@ -97,6 +109,20 @@ void Node::_notification(int p_notification) { if (data.unhandled_key_input) remove_from_group("_vp_unhandled_key_input"+itos(get_viewport()->get_instance_ID())); + + data.pause_owner=NULL; + data.network_owner=NULL; + if (data.path_cache) { + memdelete(data.path_cache); + data.path_cache=NULL; + } + } break; + case NOTIFICATION_PATH_CHANGED: { + + if (data.path_cache) { + memdelete(data.path_cache); + data.path_cache=NULL; + } } break; case NOTIFICATION_READY: { @@ -412,6 +438,640 @@ void Node::_propagate_pause_owner(Node*p_owner) { } } +void Node::set_network_mode(NetworkMode p_mode) { + + if (data.network_mode==p_mode) + return; + + bool prev_inherits=data.network_mode==NETWORK_MODE_INHERIT; + data.network_mode=p_mode; + if (!is_inside_tree()) + return; //pointless + if ((data.network_mode==NETWORK_MODE_INHERIT) == prev_inherits) + return; ///nothing changed + + Node *owner=NULL; + + if (data.network_mode==NETWORK_MODE_INHERIT) { + + if (data.parent) + owner=data.parent->data.network_owner; + } else { + owner=this; + } + + _propagate_network_owner(owner); + + + +} + +Node::NetworkMode Node::get_network_mode() const { + + return data.network_mode; +} + +bool Node::is_network_master() const { + + ERR_FAIL_COND_V(!is_inside_tree(),false); + + switch(data.network_mode) { + case NETWORK_MODE_INHERIT: { + + if (data.network_owner) + return data.network_owner->is_network_master(); + else + return get_tree()->is_network_server(); + } break; + case NETWORK_MODE_MASTER: { + + return true; + } break; + case NETWORK_MODE_SLAVE: { + return false; + } break; + } + + return false; +} + + + +void Node::_propagate_network_owner(Node*p_owner) { + + if (data.network_mode!=NETWORK_MODE_INHERIT) + return; + data.network_owner=p_owner; + for(int i=0;i<data.children.size();i++) { + + data.children[i]->_propagate_network_owner(p_owner); + } +} + +/***** RPC CONFIG ********/ + +void Node::rpc_config(const StringName& p_method,RPCMode p_mode) { + + if (p_mode==RPC_MODE_DISABLED) { + data.rpc_methods.erase(p_method); + } else { + data.rpc_methods[p_method]=p_mode; + }; +} + +void Node::rset_config(const StringName& p_property,RPCMode p_mode) { + + if (p_mode==RPC_MODE_DISABLED) { + data.rpc_properties.erase(p_property); + } else { + data.rpc_properties[p_property]=p_mode; + }; +} + +/***** RPC FUNCTIONS ********/ + +void Node::rpc(const StringName& p_method,VARIANT_ARG_DECLARE) { + + VARIANT_ARGPTRS; + + int argc=0; + for(int i=0;i<VARIANT_ARG_MAX;i++) { + if (argptr[i]->get_type()==Variant::NIL) + break; + argc++; + } + + rpcp(0,false,p_method,argptr,argc); +} + + +void Node::rpc_id(int p_peer_id,const StringName& p_method,VARIANT_ARG_DECLARE) { + + VARIANT_ARGPTRS; + + int argc=0; + for(int i=0;i<VARIANT_ARG_MAX;i++) { + if (argptr[i]->get_type()==Variant::NIL) + break; + argc++; + } + + rpcp(p_peer_id,false,p_method,argptr,argc); +} + + +void Node::rpc_unreliable(const StringName& p_method,VARIANT_ARG_DECLARE) { + + VARIANT_ARGPTRS; + + int argc=0; + for(int i=0;i<VARIANT_ARG_MAX;i++) { + if (argptr[i]->get_type()==Variant::NIL) + break; + argc++; + } + + rpcp(0,true,p_method,argptr,argc); +} + + +void Node::rpc_unreliable_id(int p_peer_id,const StringName& p_method,VARIANT_ARG_DECLARE) { + + VARIANT_ARGPTRS; + + int argc=0; + for(int i=0;i<VARIANT_ARG_MAX;i++) { + if (argptr[i]->get_type()==Variant::NIL) + break; + argc++; + } + + rpcp(p_peer_id,true,p_method,argptr,argc); +} + + +Variant Node::_rpc_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error) { + + if (p_argcount<1) { + r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.argument=1; + return Variant(); + } + + if (p_args[0]->get_type()!=Variant::STRING) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::STRING; + return Variant(); + } + + StringName method = *p_args[0]; + + rpcp(0,false,method,&p_args[1],p_argcount-1); + + r_error.error=Variant::CallError::CALL_OK; + return Variant(); +} + + +Variant Node::_rpc_id_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error) { + + if (p_argcount<2) { + r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.argument=2; + return Variant(); + } + + if (p_args[0]->get_type()!=Variant::INT) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::INT; + return Variant(); + } + + if (p_args[1]->get_type()!=Variant::STRING) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=1; + r_error.expected=Variant::STRING; + return Variant(); + } + + int peer_id = *p_args[0]; + StringName method = *p_args[1]; + + rpcp(peer_id,false,method,&p_args[2],p_argcount-2); + + r_error.error=Variant::CallError::CALL_OK; + return Variant(); +} + + +Variant Node::_rpc_unreliable_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error) { + + if (p_argcount<1) { + r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.argument=1; + return Variant(); + } + + if (p_args[0]->get_type()!=Variant::STRING) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::STRING; + return Variant(); + } + + StringName method = *p_args[0]; + + rpcp(0,true,method,&p_args[1],p_argcount-1); + + r_error.error=Variant::CallError::CALL_OK; + return Variant(); +} + + +Variant Node::_rpc_unreliable_id_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error) { + + if (p_argcount<2) { + r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.argument=2; + return Variant(); + } + + if (p_args[0]->get_type()!=Variant::INT) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::INT; + return Variant(); + } + + if (p_args[1]->get_type()!=Variant::STRING) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=1; + r_error.expected=Variant::STRING; + return Variant(); + } + + int peer_id = *p_args[0]; + StringName method = *p_args[1]; + + rpcp(peer_id,true,method,&p_args[2],p_argcount-2); + + r_error.error=Variant::CallError::CALL_OK; + return Variant(); +} + +#if 0 +Variant Node::_rpc_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error) { + + if (p_argcount<1) { + r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.argument=1; + return Variant(); + } + + if (p_args[0]->get_type()!=Variant::STRING) { + r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument=0; + r_error.expected=Variant::STRING; + return Variant(); + } + + StringName method = *p_args[0]; + + rpcp(method,&p_args[1],p_argcount-1); + + r_error.error=Variant::CallError::CALL_OK; + return Variant(); +} + +#endif +void Node::rpcp(int p_peer_id,bool p_unreliable,const StringName& p_method,const Variant** p_arg,int p_argcount) { + + ERR_FAIL_COND(!is_inside_tree()); + + bool skip_rpc=false; + + if (p_peer_id==0 || p_peer_id==get_tree()->get_network_unique_id() || (p_peer_id<0 && p_peer_id!=-get_tree()->get_network_unique_id())) { + //check that send mode can use local call + + + bool call_local=false; + + + + Map<StringName,RPCMode>::Element *E = data.rpc_methods.find(p_method); + if (E) { + + switch(E->get()) { + + case RPC_MODE_DISABLED: { + //do nothing + } break; + case RPC_MODE_REMOTE: { + //do nothing also, no need to call local + } break; + case RPC_MODE_SYNC: { + //call it, sync always results in call + call_local=true; + } break; + case RPC_MODE_MASTER: { + call_local=is_network_master(); + if (call_local) { + skip_rpc=true; //no other master so.. + } + } break; + case RPC_MODE_SLAVE: { + call_local=!is_network_master(); + } break; + + } + } + + + if (call_local) { + Variant::CallError ce; + call(p_method,p_arg,p_argcount,ce); + if (ce.error!=Variant::CallError::CALL_OK) { + String error = Variant::get_call_error_text(this,p_method,p_arg,p_argcount,ce); + error="rpc() aborted in local call: - "+error; + ERR_PRINTS(error); + return; + } + } else if (get_script_instance()){ + //attempt with script + ScriptInstance::RPCMode rpc_mode = get_script_instance()->get_rpc_mode(p_method); + + switch(rpc_mode) { + + case ScriptInstance::RPC_MODE_DISABLED: { + //do nothing + } break; + case ScriptInstance::RPC_MODE_REMOTE: { + //do nothing also, no need to call local + } break; + case ScriptInstance::RPC_MODE_SYNC: { + //call it, sync always results in call + call_local=true; + } break; + case ScriptInstance::RPC_MODE_MASTER: { + call_local=is_network_master(); + if (call_local) { + skip_rpc=true; //no other master so.. + } + } break; + case ScriptInstance::RPC_MODE_SLAVE: { + call_local=!is_network_master(); + } break; + } + + if (call_local) { + Variant::CallError ce; + ce.error=Variant::CallError::CALL_OK; + get_script_instance()->call(p_method,p_arg,p_argcount,ce); + if (ce.error!=Variant::CallError::CALL_OK) { + String error = Variant::get_call_error_text(this,p_method,p_arg,p_argcount,ce); + error="rpc() aborted in script local call: - "+error; + ERR_PRINTS(error); + return; + } + } + } + } + + if (skip_rpc) + return; + + + get_tree()->_rpc(this,p_peer_id,p_unreliable,false,p_method,p_arg,p_argcount); + +} + + +/******** RSET *********/ + + +void Node::rsetp(int p_peer_id,bool p_unreliable,const StringName& p_property,const Variant& p_value) { + + ERR_FAIL_COND(!is_inside_tree()); + + bool skip_rset=false; + + if (p_peer_id==0 || p_peer_id==get_tree()->get_network_unique_id() || (p_peer_id<0 && p_peer_id!=-get_tree()->get_network_unique_id())) { + //check that send mode can use local call + + + bool set_local=false; + + Map<StringName,RPCMode>::Element *E = data.rpc_properties.find(p_property); + if (E) { + + switch(E->get()) { + + case RPC_MODE_DISABLED: { + //do nothing + } break; + case RPC_MODE_REMOTE: { + //do nothing also, no need to call local + } break; + case RPC_MODE_SYNC: { + //call it, sync always results in call + set_local=true; + } break; + case RPC_MODE_MASTER: { + set_local=is_network_master(); + if (set_local) { + skip_rset=true; + } + + } break; + case RPC_MODE_SLAVE: { + set_local=!is_network_master(); + } break; + + } + } + + + if (set_local) { + bool valid; + set(p_property,p_value,&valid); + + if (!valid) { + String error="rset() aborted in local set, property not found: - "+String(p_property); + ERR_PRINTS(error); + return; + } + } else if (get_script_instance()){ + //attempt with script + ScriptInstance::RPCMode rpc_mode = get_script_instance()->get_rset_mode(p_property); + + switch(rpc_mode) { + + case ScriptInstance::RPC_MODE_DISABLED: { + //do nothing + } break; + case ScriptInstance::RPC_MODE_REMOTE: { + //do nothing also, no need to call local + } break; + case ScriptInstance::RPC_MODE_SYNC: { + //call it, sync always results in call + set_local=true; + } break; + case ScriptInstance::RPC_MODE_MASTER: { + set_local=is_network_master(); + if (set_local) { + skip_rset=true; + } + } break; + case ScriptInstance::RPC_MODE_SLAVE: { + set_local=!is_network_master(); + } break; + } + + if (set_local) { + + bool valid = get_script_instance()->set(p_property,p_value); + + if (!valid) { + String error="rset() aborted in local script set, property not found: - "+String(p_property); + ERR_PRINTS(error); + return; + } + } + + } + } + + if (skip_rset) + return; + + const Variant*vptr = &p_value; + + get_tree()->_rpc(this,p_peer_id,p_unreliable,true,p_property,&vptr,1); + +} + + + +void Node::rset(const StringName& p_property,const Variant& p_value) { + + rsetp(0,false,p_property,p_value); + +} + +void Node::rset_id(int p_peer_id,const StringName& p_property,const Variant& p_value) { + + rsetp(p_peer_id,false,p_property,p_value); + +} + +void Node::rset_unreliable(const StringName& p_property,const Variant& p_value) { + + rsetp(0,true,p_property,p_value); + +} + +void Node::rset_unreliable_id(int p_peer_id,const StringName& p_property,const Variant& p_value) { + + rsetp(p_peer_id,true,p_property,p_value); + +} + +//////////// end of rpc + +bool Node::can_call_rpc(const StringName& p_method) const { + + const Map<StringName,RPCMode>::Element *E = data.rpc_methods.find(p_method); + if (E) { + + switch(E->get()) { + + case RPC_MODE_DISABLED: { + return false; + } break; + case RPC_MODE_REMOTE: { + return true; + } break; + case RPC_MODE_SYNC: { + return true; + } break; + case RPC_MODE_MASTER: { + return is_network_master(); + } break; + case RPC_MODE_SLAVE: { + return !is_network_master(); + } break; + } + } + + + if (get_script_instance()){ + //attempt with script + ScriptInstance::RPCMode rpc_mode = get_script_instance()->get_rpc_mode(p_method); + + switch(rpc_mode) { + + case ScriptInstance::RPC_MODE_DISABLED: { + return false; + } break; + case ScriptInstance::RPC_MODE_REMOTE: { + return true; + } break; + case ScriptInstance::RPC_MODE_SYNC: { + return true; + } break; + case ScriptInstance::RPC_MODE_MASTER: { + return is_network_master(); + } break; + case ScriptInstance::RPC_MODE_SLAVE: { + return !is_network_master(); + } break; + } + + } + + ERR_PRINTS("RPC on unauthorized method attempted: "+String(p_method)+" on base: "+String(Variant(this))); + return false; +} + +bool Node::can_call_rset(const StringName& p_property) const { + + const Map<StringName,RPCMode>::Element *E = data.rpc_properties.find(p_property); + if (E) { + + switch(E->get()) { + + case RPC_MODE_DISABLED: { + return false; + } break; + case RPC_MODE_REMOTE: { + return true; + } break; + case RPC_MODE_SYNC: { + return true; + } break; + case RPC_MODE_MASTER: { + return is_network_master(); + } break; + case RPC_MODE_SLAVE: { + return !is_network_master(); + } break; + } + } + + + if (get_script_instance()){ + //attempt with script + ScriptInstance::RPCMode rpc_mode = get_script_instance()->get_rset_mode(p_property); + + switch(rpc_mode) { + + case ScriptInstance::RPC_MODE_DISABLED: { + return false; + } break; + case ScriptInstance::RPC_MODE_REMOTE: { + return true; + } break; + case ScriptInstance::RPC_MODE_SYNC: { + return true; + } break; + case ScriptInstance::RPC_MODE_MASTER: { + return is_network_master(); + } break; + case ScriptInstance::RPC_MODE_SLAVE: { + return !is_network_master(); + } break; + } + + } + + ERR_PRINTS("RSET on unauthorized property attempted: "+String(p_property)+" on base: "+String(Variant(this))); + + return false; +} + + bool Node::can_process() const { ERR_FAIL_COND_V( !is_inside_tree(), false ); @@ -567,6 +1227,8 @@ void Node::set_name(const String& p_name) { data.parent->_validate_child_name(this); } + propagate_notification(NOTIFICATION_PATH_CHANGED); + if (is_inside_tree()) { emit_signal("renamed"); @@ -1210,6 +1872,10 @@ NodePath Node::get_path_to(const Node *p_node) const { NodePath Node::get_path() const { ERR_FAIL_COND_V(!is_inside_tree(),NodePath()); + + if (data.path_cache) + return *data.path_cache; + const Node *n = this; Vector<StringName> path; @@ -1221,7 +1887,9 @@ NodePath Node::get_path() const { path.invert(); - return NodePath( path, true ); + data.path_cache = memnew( NodePath( path, true ) ); + + return *data.path_cache; } bool Node::is_in_group(const StringName& p_identifier) const { @@ -2212,7 +2880,13 @@ void Node::_bind_methods() { ObjectTypeDB::bind_method(_MD("queue_free"),&Node::queue_delete); + ObjectTypeDB::bind_method(_MD("set_network_mode","mode"),&Node::set_network_mode); + ObjectTypeDB::bind_method(_MD("get_network_mode"),&Node::get_network_mode); + + ObjectTypeDB::bind_method(_MD("is_network_master"),&Node::is_network_master); + ObjectTypeDB::bind_method(_MD("rpc_config","method","mode"),&Node::rpc_config); + ObjectTypeDB::bind_method(_MD("rset_config","property","mode"),&Node::rset_config); #ifdef TOOLS_ENABLED @@ -2222,6 +2896,33 @@ void Node::_bind_methods() { #endif + { + MethodInfo mi; + + mi.arguments.push_back( PropertyInfo( Variant::STRING, "method")); + + + mi.name="rpc"; + ObjectTypeDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"rpc",&Node::_rpc_bind,mi); + mi.name="rpc_unreliable"; + ObjectTypeDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"rpc_unreliable",&Node::_rpc_unreliable_bind,mi); + + mi.arguments.push_front( PropertyInfo( Variant::INT, "peer_id") ); + + mi.name="rpc_id"; + ObjectTypeDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"rpc_id",&Node::_rpc_id_bind,mi); + mi.name="rpc_unreliable_id"; + ObjectTypeDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"rpc_unreliable_id",&Node::_rpc_unreliable_id_bind,mi); + + + } + + ObjectTypeDB::bind_method(_MD("rset","property","value:Variant"),&Node::rset); + ObjectTypeDB::bind_method(_MD("rset_id","peer_id","property","value:Variant"),&Node::rset_id); + ObjectTypeDB::bind_method(_MD("rset_unreliable","property","value:Variant"),&Node::rset_unreliable); + ObjectTypeDB::bind_method(_MD("rset_unreliable_id","peer_id","property","value:Variant"),&Node::rset_unreliable_id); + + BIND_CONSTANT( NOTIFICATION_ENTER_TREE ); BIND_CONSTANT( NOTIFICATION_EXIT_TREE ); BIND_CONSTANT( NOTIFICATION_MOVED_IN_PARENT ); @@ -2236,8 +2937,18 @@ void Node::_bind_methods() { BIND_CONSTANT( NOTIFICATION_INSTANCED ); BIND_CONSTANT( NOTIFICATION_DRAG_BEGIN ); BIND_CONSTANT( NOTIFICATION_DRAG_END ); + BIND_CONSTANT( NOTIFICATION_PATH_CHANGED); + BIND_CONSTANT( NETWORK_MODE_INHERIT ); + BIND_CONSTANT( NETWORK_MODE_MASTER ); + BIND_CONSTANT( NETWORK_MODE_SLAVE ); + + BIND_CONSTANT( RPC_MODE_DISABLED ); + BIND_CONSTANT( RPC_MODE_REMOTE ); + BIND_CONSTANT( RPC_MODE_SYNC ); + BIND_CONSTANT( RPC_MODE_MASTER ); + BIND_CONSTANT( RPC_MODE_SLAVE ); BIND_CONSTANT( PAUSE_MODE_INHERIT ); BIND_CONSTANT( PAUSE_MODE_STOP ); @@ -2286,11 +2997,15 @@ Node::Node() { data.unhandled_key_input=false; data.pause_mode=PAUSE_MODE_INHERIT; data.pause_owner=NULL; + data.network_mode=NETWORK_MODE_INHERIT; + data.network_owner=NULL; + data.path_cache=NULL; data.parent_owned=false; data.in_constructor=true; data.viewport=NULL; data.use_placeholder=false; data.display_folded=false; + } Node::~Node() { diff --git a/scene/main/node.h b/scene/main/node.h index 18e403cd61..3568da2ab0 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -53,6 +53,21 @@ public: PAUSE_MODE_PROCESS }; + enum NetworkMode { + + NETWORK_MODE_INHERIT, + NETWORK_MODE_MASTER, + NETWORK_MODE_SLAVE + }; + + enum RPCMode { + + RPC_MODE_DISABLED, //no rpc for this method, calls to this will be blocked (default) + RPC_MODE_REMOTE, // using rpc() on it will call method / set property in all other peers + RPC_MODE_SYNC, // using rpc() on it will call method / set property in all other peers and locally + RPC_MODE_MASTER, // usinc rpc() on it will call method on wherever the master is, be it local or remote + RPC_MODE_SLAVE, // usinc rpc() on it will call method for all slaves, be it local or remote + }; struct Comparator { @@ -68,6 +83,8 @@ private: GroupData() { persistent=false; } }; + + struct Data { String filename; @@ -98,6 +115,13 @@ private: PauseMode pause_mode; Node *pause_owner; + + NetworkMode network_mode; + Node *network_owner; + Map<StringName,RPCMode> rpc_methods; + Map<StringName,RPCMode> rpc_properties; + + // variables used to properly sort the node when processing, ignored otherwise //should move all the stuff below to bits bool fixed_process; @@ -113,6 +137,8 @@ private: bool display_folded; + mutable NodePath *path_cache; + } data; @@ -134,6 +160,7 @@ private: void _propagate_validate_owner(); void _print_stray_nodes(); void _propagate_pause_owner(Node*p_owner); + void _propagate_network_owner(Node*p_owner); Array _get_node_and_resource(const NodePath& p_path); void _duplicate_signals(const Node* p_original,Node* p_copy) const; @@ -143,6 +170,11 @@ private: Array _get_children() const; Array _get_groups() const; + Variant _rpc_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error); + Variant _rpc_unreliable_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error); + Variant _rpc_id_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error); + Variant _rpc_unreliable_id_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error); + friend class SceneTree; void _set_tree(SceneTree *p_tree); @@ -186,6 +218,7 @@ public: NOTIFICATION_INSTANCED=20, NOTIFICATION_DRAG_BEGIN=21, NOTIFICATION_DRAG_END=22, + NOTIFICATION_PATH_CHANGED=23, }; /* NODE/TREE */ @@ -331,7 +364,32 @@ public: void set_display_folded(bool p_folded); bool is_displayed_folded() const; - /* CANVAS */ + /* NETWORK */ + + void set_network_mode(NetworkMode p_mode); + NetworkMode get_network_mode() const; + bool is_network_master() const; + + void rpc_config(const StringName& p_method,RPCMode p_mode); // config a local method for RPC + void rset_config(const StringName& p_property,RPCMode p_mode); // config a local property for RPC + + void rpc(const StringName& p_method,VARIANT_ARG_LIST); //rpc call, honors RPCMode + void rpc_unreliable(const StringName& p_method,VARIANT_ARG_LIST); //rpc call, honors RPCMode + void rpc_id(int p_peer_id,const StringName& p_method,VARIANT_ARG_LIST); //rpc call, honors RPCMode + void rpc_unreliable_id(int p_peer_id,const StringName& p_method,VARIANT_ARG_LIST); //rpc call, honors RPCMode + + void rpcp(int p_peer_id,bool p_unreliable,const StringName& p_method,const Variant** p_arg,int p_argcount); + + void rset(const StringName& p_property, const Variant& p_value); //remote set call, honors RPCMode + void rset_unreliable(const StringName& p_property,const Variant& p_value); //remote set call, honors RPCMode + void rset_id(int p_peer_id,const StringName& p_property,const Variant& p_value); //remote set call, honors RPCMode + void rset_unreliable_id(int p_peer_id,const StringName& p_property,const Variant& p_value); //remote set call, honors RPCMode + + void rsetp(int p_peer_id,bool p_unreliable,const StringName& p_property,const Variant& p_value); + + bool can_call_rpc(const StringName& p_method) const; + bool can_call_rset(const StringName& p_property) const; + Node(); ~Node(); diff --git a/scene/main/scene_main_loop.cpp b/scene/main/scene_main_loop.cpp index a7ef7ca7c1..e3472c074a 100644 --- a/scene/main/scene_main_loop.cpp +++ b/scene/main/scene_main_loop.cpp @@ -44,6 +44,30 @@ #include "scene/resources/packed_scene.h" #include "scene/resources/material.h" #include "scene/resources/mesh.h" +#include "io/marshalls.h" + +void SceneTreeTimer::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_time_left","time"),&SceneTreeTimer::set_time_left); + ObjectTypeDB::bind_method(_MD("get_time_left"),&SceneTreeTimer::get_time_left); + + ADD_SIGNAL(MethodInfo("timeout")); +} + + +void SceneTreeTimer::set_time_left(float p_time) { + time_left=p_time; +} + +float SceneTreeTimer::get_time_left() const { + return time_left; +} + + +SceneTreeTimer::SceneTreeTimer() { + time_left=0; +} + void SceneTree::tree_changed() { @@ -521,6 +545,8 @@ bool SceneTree::idle(float p_time){ idle_process_time=p_time; + _network_poll(); + emit_signal("idle_frame"); _flush_transform_notifications(); @@ -547,6 +573,23 @@ bool SceneTree::idle(float p_time){ _flush_delete_queue(); + //go through timers + + for (List<Ref<SceneTreeTimer> >::Element *E=timers.front();E;) { + + List<Ref<SceneTreeTimer> >::Element *N = E->next(); + + float time_left = E->get()->get_time_left(); + time_left-=p_time; + E->get()->set_time_left(time_left); + + if (time_left<0) { + E->get()->emit_signal("timeout"); + timers.erase(E); + } + E=N; + } + return _quit; } @@ -1604,6 +1647,510 @@ void SceneTree::drop_files(const Vector<String>& p_files,int p_from_screen) { MainLoop::drop_files(p_files,p_from_screen); } + +Ref<SceneTreeTimer> SceneTree::create_timer(float p_delay_sec) { + + Ref<SceneTreeTimer> stt; + stt.instance(); + stt->set_time_left(p_delay_sec); + timers.push_back(stt); + return stt; +} + +void SceneTree::_network_peer_connected(int p_id) { + + + connected_peers.insert(p_id); + path_get_cache.insert(p_id,PathGetCache()); + + + emit_signal("network_peer_connected",p_id); +} + +void SceneTree::_network_peer_disconnected(int p_id) { + + connected_peers.erase(p_id); + path_get_cache.erase(p_id); //I no longer need your cache, sorry + emit_signal("network_peer_disconnected",p_id); +} + +void SceneTree::_connected_to_server() { + + emit_signal("connected_to_server"); +} + +void SceneTree::_connection_failed() { + + emit_signal("connection_failed"); +} + +void SceneTree::_server_disconnected() { + + emit_signal("server_disconnected"); +} + +void SceneTree::set_network_peer(const Ref<NetworkedMultiplayerPeer>& p_network_peer) { + if (network_peer.is_valid()) { + network_peer->disconnect("peer_connected",this,"_network_peer_connected"); + network_peer->disconnect("peer_disconnected",this,"_network_peer_disconnected"); + network_peer->disconnect("connection_succeeded",this,"_connected_to_server"); + network_peer->disconnect("connection_failed",this,"_connection_failed"); + network_peer->disconnect("server_disconnected",this,"_server_disconnected"); + connected_peers.clear(); + path_get_cache.clear(); + path_send_cache.clear(); + last_send_cache_id=1; + } + + ERR_EXPLAIN("Supplied NetworkedNetworkPeer must be connecting or connected."); + ERR_FAIL_COND(p_network_peer.is_valid() && p_network_peer->get_connection_status()==NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED); + + network_peer=p_network_peer; + + if (network_peer.is_valid()) { + network_peer->connect("peer_connected",this,"_network_peer_connected"); + network_peer->connect("peer_disconnected",this,"_network_peer_disconnected"); + network_peer->connect("connection_succeeded",this,"_connected_to_server"); + network_peer->connect("connection_failed",this,"_connection_failed"); + network_peer->connect("server_disconnected",this,"_server_disconnected"); + } +} + +bool SceneTree::is_network_server() const { + + ERR_FAIL_COND_V(!network_peer.is_valid(),false); + return network_peer->is_server(); + +} + +int SceneTree::get_network_unique_id() const { + + ERR_FAIL_COND_V(!network_peer.is_valid(),0); + return network_peer->get_unique_id(); +} + +void SceneTree::set_refuse_new_network_connections(bool p_refuse) { + ERR_FAIL_COND(!network_peer.is_valid()); + network_peer->set_refuse_new_connections(p_refuse); +} + +bool SceneTree::is_refusing_new_network_connections() const { + + ERR_FAIL_COND_V(!network_peer.is_valid(),false); + + return network_peer->is_refusing_new_connections(); + +} + + +void SceneTree::_rpc(Node* p_from,int p_to,bool p_unreliable,bool p_set,const StringName& p_name,const Variant** p_arg,int p_argcount) { + + if (network_peer.is_null()) { + ERR_EXPLAIN("Attempt to remote call/set when networking is not active in SceneTree."); + ERR_FAIL(); + } + + if (network_peer->get_connection_status()==NetworkedMultiplayerPeer::CONNECTION_CONNECTING) { + ERR_EXPLAIN("Attempt to remote call/set when networking is not connected yet in SceneTree."); + ERR_FAIL(); + } + + if (network_peer->get_connection_status()==NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED) { + ERR_EXPLAIN("Attempt to remote call/set when networking is disconnected."); + ERR_FAIL(); + } + + if (p_argcount>255) { + ERR_EXPLAIN("Too many arguments >255."); + ERR_FAIL(); + } + + if (p_to!=0 && !connected_peers.has(ABS(p_to))) { + if (p_to==get_network_unique_id()) { + ERR_EXPLAIN("Attempt to remote call/set yourself! unique ID: "+itos(get_network_unique_id())); + } else { + ERR_EXPLAIN("Attempt to remote call unexisting ID: "+itos(p_to)); + + } + + ERR_FAIL(); + } + + NodePath from_path = p_from->get_path(); + ERR_FAIL_COND(from_path.is_empty()); + + + + //see if the path is cached + PathSentCache *psc = path_send_cache.getptr(from_path); + if (!psc) { + //path is not cached, create + path_send_cache[from_path]=PathSentCache(); + psc = path_send_cache.getptr(from_path); + psc->id=last_send_cache_id++; + + } + + + //create base packet, lots of harcode because it must be tight + + int ofs=0; + +#define MAKE_ROOM(m_amount) if (packet_cache.size() < m_amount) packet_cache.resize(m_amount); + + //encode type + MAKE_ROOM(1); + packet_cache[0]=p_set ? NETWORK_COMMAND_REMOTE_SET : NETWORK_COMMAND_REMOTE_CALL; + ofs+=1; + + //encode ID + MAKE_ROOM(ofs+4); + encode_uint32(psc->id,&packet_cache[ofs]); + ofs+=4; + + //encode function name + CharString name = String(p_name).utf8(); + int len = encode_cstring(name.get_data(),NULL); + MAKE_ROOM(ofs+len); + encode_cstring(name.get_data(),&packet_cache[ofs]); + ofs+=len; + + if (p_set) { + //set argument + Error err = encode_variant(*p_arg[0],NULL,len); + ERR_FAIL_COND(err!=OK); + MAKE_ROOM(ofs+len); + encode_variant(*p_arg[0],&packet_cache[ofs],len); + ofs+=len; + + } else { + //call arguments + MAKE_ROOM(ofs+1); + packet_cache[ofs]=p_argcount; + ofs+=1; + for(int i=0;i<p_argcount;i++) { + Error err = encode_variant(*p_arg[i],NULL,len); + ERR_FAIL_COND(err!=OK); + MAKE_ROOM(ofs+len); + encode_variant(*p_arg[i],&packet_cache[ofs],len); + ofs+=len; + } + + } + + //see if all peers have cached path (is so, call can be fast) + bool has_all_peers=true; + + List<int> peers_to_add; //if one is missing, take note to add it + + for (Set<int>::Element *E=connected_peers.front();E;E=E->next()) { + + if (p_to<0 && E->get()==-p_to) + continue; //continue, excluded + + if (p_to>0 && E->get()!=p_to) + continue; //continue, not for this peer + + Map<int,bool>::Element *F = psc->confirmed_peers.find(E->get()); + + if (!F || F->get()==false) { + //path was not cached, or was cached but is unconfirmed + if (!F) { + //not cached at all, take note + peers_to_add.push_back(E->get()); + } + + has_all_peers=false; + } + } + + //those that need to be added, send a message for this + + for (List<int>::Element *E=peers_to_add.front();E;E=E->next()) { + + //encode function name + CharString pname = String(from_path).utf8(); + int len = encode_cstring(pname.get_data(),NULL); + + Vector<uint8_t> packet; + + packet.resize(1+4+len); + packet[0]=NETWORK_COMMAND_SIMPLIFY_PATH; + encode_uint32(psc->id,&packet[1]); + encode_cstring(pname.get_data(),&packet[5]); + + network_peer->set_target_peer(E->get()); //to all of you + network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); + network_peer->put_packet(packet.ptr(),packet.size()); + + psc->confirmed_peers.insert(E->get(),false); //insert into confirmed, but as false since it was not confirmed + } + + //take chance and set transfer mode, since all send methods will use it + network_peer->set_transfer_mode(p_unreliable ? NetworkedMultiplayerPeer::TRANSFER_MODE_UNRELIABLE : NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); + + if (has_all_peers) { + + //they all have verified paths, so send fast + network_peer->set_target_peer(p_to); //to all of you + network_peer->put_packet(packet_cache.ptr(),ofs); //a message with love + } else { + //not all verified path, so send one by one + + //apend path at the end, since we will need it for some packets + CharString pname = String(from_path).utf8(); + int path_len = encode_cstring(pname.get_data(),NULL); + MAKE_ROOM(ofs+path_len); + encode_cstring(pname.get_data(),&packet_cache[ofs]); + + + for (Set<int>::Element *E=connected_peers.front();E;E=E->next()) { + + if (p_to<0 && E->get()==-p_to) + continue; //continue, excluded + + if (p_to>0 && E->get()!=p_to) + continue; //continue, not for this peer + + Map<int,bool>::Element *F = psc->confirmed_peers.find(E->get()); + ERR_CONTINUE(!F);//should never happen + + network_peer->set_target_peer(E->get()); //to this one specifically + + if (F->get()==true) { + //this one confirmed path, so use id + encode_uint32(psc->id,&packet_cache[1]); + network_peer->put_packet(packet_cache.ptr(),ofs); + } else { + //this one did not confirm path yet, so use entire path (sorry!) + encode_uint32(0x80000000|ofs,&packet_cache[1]); //offset to path and flag + network_peer->put_packet(packet_cache.ptr(),ofs+path_len); + } + + } + } +} + + +void SceneTree::_network_process_packet(int p_from, const uint8_t* p_packet, int p_packet_len) { + + ERR_FAIL_COND(p_packet_len<5); + + uint8_t packet_type = p_packet[0]; + + switch(packet_type) { + + case NETWORK_COMMAND_REMOTE_CALL: + case NETWORK_COMMAND_REMOTE_SET: { + + ERR_FAIL_COND(p_packet_len<5); + uint32_t target = decode_uint32(&p_packet[1]); + + + Node *node=NULL; + + if (target&0x80000000) { + + int ofs = target&0x7FFFFFFF; + ERR_FAIL_COND(ofs>=p_packet_len); + + String paths; + paths.parse_utf8((const char*)&p_packet[ofs],p_packet_len-ofs); + + NodePath np = paths; + + node = get_root()->get_node(np); + if (node==NULL) { + ERR_EXPLAIN("Failed to get path from RPC: "+String(np)); + ERR_FAIL_COND(node==NULL); + } + } else { + + int id = target; + + Map<int,PathGetCache>::Element *E=path_get_cache.find(p_from); + ERR_FAIL_COND(!E); + + Map<int,PathGetCache::NodeInfo>::Element *F=E->get().nodes.find(id); + ERR_FAIL_COND(!F); + + PathGetCache::NodeInfo *ni = &F->get(); + //do proper caching later + + node = get_root()->get_node(ni->path); + if (node==NULL) { + ERR_EXPLAIN("Failed to get cached path from RPC: "+String(ni->path)); + ERR_FAIL_COND(node==NULL); + } + + + } + + ERR_FAIL_COND(p_packet_len<6); + + //detect cstring end + int len_end=5; + for(;len_end<p_packet_len;len_end++) { + if (p_packet[len_end]==0) { + break; + } + } + + ERR_FAIL_COND(len_end>=p_packet_len); + + StringName name = String::utf8((const char*)&p_packet[5]); + + + + + if (packet_type==NETWORK_COMMAND_REMOTE_CALL) { + + if (!node->can_call_rpc(name)) + return; + + int ofs = len_end+1; + + ERR_FAIL_COND(ofs>=p_packet_len); + + int argc = p_packet[ofs]; + Vector<Variant> args; + Vector<const Variant*> argp; + args.resize(argc); + argp.resize(argc); + + ofs++; + + for(int i=0;i<argc;i++) { + + ERR_FAIL_COND(ofs>=p_packet_len); + int vlen; + Error err = decode_variant(args[i],&p_packet[ofs],p_packet_len-ofs,&vlen); + ERR_FAIL_COND(err!=OK); + //args[i]=p_packet[3+i]; + argp[i]=&args[i]; + ofs+=vlen; + } + + Variant::CallError ce; + + node->call(name,argp.ptr(),argc,ce); + if (ce.error!=Variant::CallError::CALL_OK) { + String error = Variant::get_call_error_text(node,name,argp.ptr(),argc,ce); + error="RPC - "+error; + ERR_PRINTS(error); + } + + } else { + + if (!node->can_call_rset(name)) + return; + + int ofs = len_end+1; + + ERR_FAIL_COND(ofs>=p_packet_len); + + Variant value; + decode_variant(value,&p_packet[ofs],p_packet_len-ofs); + + bool valid; + + node->set(name,value,&valid); + if (!valid) { + String error = "Error setting remote property '"+String(name)+"', not found in object of type "+node->get_type(); + ERR_PRINTS(error); + } + } + + } break; + case NETWORK_COMMAND_SIMPLIFY_PATH: { + + ERR_FAIL_COND(p_packet_len<5); + int id = decode_uint32(&p_packet[1]); + + String paths; + paths.parse_utf8((const char*)&p_packet[5],p_packet_len-5); + + NodePath path = paths; + + if (!path_get_cache.has(p_from)) { + path_get_cache[p_from]=PathGetCache(); + } + + PathGetCache::NodeInfo ni; + ni.path=path; + ni.instance=0; + + path_get_cache[p_from].nodes[id]=ni; + + + { + //send ack + + //encode path + CharString pname = String(path).utf8(); + int len = encode_cstring(pname.get_data(),NULL); + + Vector<uint8_t> packet; + + packet.resize(1+len); + packet[0]=NETWORK_COMMAND_CONFIRM_PATH; + encode_cstring(pname.get_data(),&packet[1]); + + network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); + network_peer->set_target_peer(p_from); + network_peer->put_packet(packet.ptr(),packet.size()); + } + } break; + case NETWORK_COMMAND_CONFIRM_PATH: { + + String paths; + paths.parse_utf8((const char*)&p_packet[1],p_packet_len-1); + + NodePath path = paths; + + PathSentCache *psc = path_send_cache.getptr(path); + ERR_FAIL_COND(!psc); + + Map<int,bool>::Element *E=psc->confirmed_peers.find(p_from); + ERR_FAIL_COND(!E); + E->get()=true; + } break; + } + +} + +void SceneTree::_network_poll() { + + if (!network_peer.is_valid() || network_peer->get_connection_status()==NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED) + return; + + network_peer->poll(); + + if (!network_peer.is_valid()) //it's possible that polling might have resulted in a disconnection, so check here + return; + + while(network_peer->get_available_packet_count()) { + + int sender = network_peer->get_packet_peer(); + const uint8_t *packet; + int len; + + Error err = network_peer->get_packet(&packet,len); + if (err!=OK) { + ERR_PRINT("Error getting packet!"); + } + + _network_process_packet(sender,packet,len); + + if (!network_peer.is_valid()) { + break; //it's also possible that a packet or RPC caused a disconnection, so also check here + } + } + + +} + + void SceneTree::_bind_methods() { @@ -1634,6 +2181,8 @@ void SceneTree::_bind_methods() { ObjectTypeDB::bind_method(_MD("is_paused"),&SceneTree::is_paused); ObjectTypeDB::bind_method(_MD("set_input_as_handled"),&SceneTree::set_input_as_handled); + ObjectTypeDB::bind_method(_MD("create_timer:SceneTreeTimer","time_sec"),&SceneTree::create_timer); + ObjectTypeDB::bind_method(_MD("get_node_count"),&SceneTree::get_node_count); ObjectTypeDB::bind_method(_MD("get_frame"),&SceneTree::get_frame); @@ -1651,13 +2200,9 @@ void SceneTree::_bind_methods() { mi.arguments.push_back( PropertyInfo( Variant::INT, "flags")); mi.arguments.push_back( PropertyInfo( Variant::STRING, "group")); mi.arguments.push_back( PropertyInfo( Variant::STRING, "method")); - Vector<Variant> defargs; - for(int i=0;i<VARIANT_ARG_MAX;i++) { - mi.arguments.push_back( PropertyInfo( Variant::NIL, "arg"+itos(i))); - defargs.push_back(Variant()); - } - ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"call_group",&SceneTree::_call_group,mi,defargs); + + ObjectTypeDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"call_group",&SceneTree::_call_group,mi); ObjectTypeDB::bind_method(_MD("set_current_scene","child_node:Node"),&SceneTree::set_current_scene); ObjectTypeDB::bind_method(_MD("get_current_scene:Node"),&SceneTree::get_current_scene); @@ -1669,6 +2214,18 @@ void SceneTree::_bind_methods() { ObjectTypeDB::bind_method(_MD("_change_scene"),&SceneTree::_change_scene); + + ObjectTypeDB::bind_method(_MD("set_network_peer","peer:NetworkedMultiplayerPeer"),&SceneTree::set_network_peer); + ObjectTypeDB::bind_method(_MD("is_network_server"),&SceneTree::is_network_server); + ObjectTypeDB::bind_method(_MD("get_network_unique_id"),&SceneTree::get_network_unique_id); + ObjectTypeDB::bind_method(_MD("set_refuse_new_network_connections","refuse"),&SceneTree::set_refuse_new_network_connections); + ObjectTypeDB::bind_method(_MD("is_refusing_new_network_connections"),&SceneTree::is_refusing_new_network_connections); + ObjectTypeDB::bind_method(_MD("_network_peer_connected"),&SceneTree::_network_peer_connected); + ObjectTypeDB::bind_method(_MD("_network_peer_disconnected"),&SceneTree::_network_peer_disconnected); + ObjectTypeDB::bind_method(_MD("_connected_to_server"),&SceneTree::_connected_to_server); + ObjectTypeDB::bind_method(_MD("_connection_failed"),&SceneTree::_connection_failed); + ObjectTypeDB::bind_method(_MD("_server_disconnected"),&SceneTree::_server_disconnected); + ADD_SIGNAL( MethodInfo("tree_changed") ); ADD_SIGNAL( MethodInfo("node_removed",PropertyInfo( Variant::OBJECT, "node") ) ); ADD_SIGNAL( MethodInfo("screen_resized") ); @@ -1678,6 +2235,11 @@ void SceneTree::_bind_methods() { ADD_SIGNAL( MethodInfo("fixed_frame")); ADD_SIGNAL( MethodInfo("files_dropped",PropertyInfo(Variant::STRING_ARRAY,"files"),PropertyInfo(Variant::INT,"screen")) ); + ADD_SIGNAL( MethodInfo("network_peer_connected",PropertyInfo(Variant::INT,"id"))); + ADD_SIGNAL( MethodInfo("network_peer_disconnected",PropertyInfo(Variant::INT,"id"))); + ADD_SIGNAL( MethodInfo("connected_to_server")); + ADD_SIGNAL( MethodInfo("connection_failed")); + ADD_SIGNAL( MethodInfo("server_disconnected")); BIND_CONSTANT( GROUP_CALL_DEFAULT ); BIND_CONSTANT( GROUP_CALL_REVERSE ); @@ -1778,6 +2340,8 @@ SceneTree::SceneTree() { live_edit_root=NodePath("/root"); + last_send_cache_id=1; + #endif diff --git a/scene/main/scene_main_loop.h b/scene/main/scene_main_loop.h index 38d13c0447..1c0f88862c 100644 --- a/scene/main/scene_main_loop.h +++ b/scene/main/scene_main_loop.h @@ -35,6 +35,9 @@ #include "scene/resources/world_2d.h" #include "os/thread_safe.h" #include "self_list.h" +#include "io/networked_multiplayer_peer.h" + + /** @author Juan Linietsky <reduzio@gmail.com> */ @@ -47,6 +50,22 @@ class Viewport; class Material; class Mesh; + + +class SceneTreeTimer : public Reference { + OBJ_TYPE(SceneTreeTimer,Reference); + + float time_left; +protected: + static void _bind_methods(); +public: + + void set_time_left(float p_time); + float get_time_left() const; + + SceneTreeTimer(); +}; + class SceneTree : public MainLoop { _THREAD_SAFE_CLASS_ @@ -155,9 +174,62 @@ private: void _change_scene(Node* p_to); //void _call_group(uint32_t p_call_flags,const StringName& p_group,const StringName& p_function,const Variant& p_arg1,const Variant& p_arg2); + List<Ref<SceneTreeTimer> > timers; + + + ///network/// + + enum NetworkCommands { + NETWORK_COMMAND_REMOTE_CALL, + NETWORK_COMMAND_REMOTE_SET, + NETWORK_COMMAND_SIMPLIFY_PATH, + NETWORK_COMMAND_CONFIRM_PATH, + }; + + Ref<NetworkedMultiplayerPeer> network_peer; + + Set<int> connected_peers; + void _network_peer_connected(int p_id); + void _network_peer_disconnected(int p_id); + + void _connected_to_server(); + void _connection_failed(); + void _server_disconnected(); + + //path sent caches + struct PathSentCache { + Map<int,bool> confirmed_peers; + int id; + }; + + HashMap<NodePath,PathSentCache> path_send_cache; + int last_send_cache_id; + + //path get caches + struct PathGetCache { + struct NodeInfo { + NodePath path; + ObjectID instance; + }; + + Map<int,NodeInfo> nodes; + }; + + Map<int,PathGetCache> path_get_cache; + + Vector<uint8_t> packet_cache; + + void _network_process_packet(int p_from, const uint8_t *p_packet, int p_packet_len); + void _network_poll(); + static SceneTree *singleton; friend class Node; + + + + void _rpc(Node* p_from,int p_to,bool p_unreliable,bool p_set,const StringName& p_name,const Variant** p_arg,int p_argcount); + void tree_changed(); void node_removed(Node *p_node); @@ -233,6 +305,7 @@ friend class Viewport; #endif protected: + void _notification(int p_notification); static void _bind_methods(); @@ -339,6 +412,8 @@ public: Error change_scene_to(const Ref<PackedScene>& p_scene); Error reload_current_scene(); + Ref<SceneTreeTimer> create_timer(float p_delay_sec); + //used by Main::start, don't use otherwise void add_current_scene(Node * p_current); @@ -346,6 +421,15 @@ public: void drop_files(const Vector<String>& p_files,int p_from_screen=0); + //network API + + void set_network_peer(const Ref<NetworkedMultiplayerPeer>& p_network_peer); + bool is_network_server() const; + int get_network_unique_id() const; + + void set_refuse_new_network_connections(bool p_refuse); + bool is_refusing_new_network_connections() const; + SceneTree(); ~SceneTree(); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index f182f2c96c..7970229c06 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -2095,6 +2095,7 @@ void Viewport::_gui_input_event(InputEvent p_event) { } break; case InputEvent::ACTION: case InputEvent::JOYSTICK_BUTTON: + case InputEvent::JOYSTICK_MOTION: case InputEvent::KEY: { |