diff options
Diffstat (limited to 'scene')
-rw-r--r-- | scene/main/node.cpp | 556 | ||||
-rw-r--r-- | scene/main/node.h | 45 | ||||
-rw-r--r-- | scene/main/scene_main_loop.cpp | 116 | ||||
-rw-r--r-- | scene/main/scene_main_loop.h | 23 |
4 files changed, 650 insertions, 90 deletions
diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 0c7d569334..086b69c1c5 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -37,6 +37,7 @@ VARIANT_ENUM_CAST(Node::PauseMode); VARIANT_ENUM_CAST(Node::NetworkMode); +VARIANT_ENUM_CAST(Node::RPCMode); @@ -494,41 +495,57 @@ bool Node::is_network_master() const { return false; } -void Node::allow_remote_call(const StringName& p_method) { - data.allowed_remote_calls.insert(p_method); -} -void Node::disallow_remote_call(const StringName& p_method){ +void Node::_propagate_network_owner(Node*p_owner) { - data.allowed_remote_calls.erase(p_method); + 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); + } } -void Node::allow_remote_set(const StringName& p_property){ +/***** RPC CONFIG ********/ - data.allowed_remote_set.insert(p_property); +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::disallow_remote_set(const StringName& p_property){ - data.allowed_remote_set.erase(p_property); +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::_propagate_network_owner(Node*p_owner) { +void Node::rpc(const StringName& p_method,VARIANT_ARG_DECLARE) { - if (data.network_mode!=NETWORK_MODE_INHERIT) - return; - data.network_owner=p_owner; - for(int i=0;i<data.children.size();i++) { + VARIANT_ARGPTRS; - data.children[i]->_propagate_network_owner(p_owner); + 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::remote_call_reliable(const StringName& p_method,VARIANT_ARG_DECLARE) { +void Node::rpc_id(int p_peer_id,const StringName& p_method,VARIANT_ARG_DECLARE) { VARIANT_ARGPTRS; @@ -539,16 +556,26 @@ void Node::remote_call_reliable(const StringName& p_method,VARIANT_ARG_DECLARE) argc++; } - remote_call_reliablep(p_method,argptr,argc); + rpcp(p_peer_id,false,p_method,argptr,argc); } -void Node::remote_call_reliablep(const StringName& p_method,const Variant** p_arg,int p_argcount){ - ERR_FAIL_COND(!is_inside_tree()); - get_tree()->_remote_call(this,true,false,p_method,p_arg,p_argcount); +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::remote_call_unreliable(const StringName& p_method,VARIANT_ARG_DECLARE){ + +void Node::rpc_unreliable_id(int p_peer_id,const StringName& p_method,VARIANT_ARG_DECLARE) { VARIANT_ARGPTRS; @@ -559,35 +586,67 @@ void Node::remote_call_unreliable(const StringName& p_method,VARIANT_ARG_DECLARE argc++; } - remote_call_unreliablep(p_method,argptr,argc); - + rpcp(p_peer_id,true,p_method,argptr,argc); } -void Node::remote_call_unreliablep(const StringName& p_method,const Variant** p_arg,int p_argcount){ - ERR_FAIL_COND(!is_inside_tree()); +Variant Node::_rpc_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error) { - get_tree()->_remote_call(this,false,false,p_method,p_arg,p_argcount); -} + if (p_argcount<1) { + r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.argument=1; + return Variant(); + } -void Node::remote_set_reliable(const StringName& p_property,const Variant& p_value) { + 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]; - ERR_FAIL_COND(!is_inside_tree()); - const Variant *ptr=&p_value; + rpcp(0,false,method,&p_args[1],p_argcount-1); - get_tree()->_remote_call(this,true,true,p_property,&ptr,1); + r_error.error=Variant::CallError::CALL_OK; + return Variant(); } -void Node::remote_set_unreliable(const StringName& p_property,const Variant& p_value){ - ERR_FAIL_COND(!is_inside_tree()); - const Variant *ptr=&p_value; +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(); + } - get_tree()->_remote_call(this,false,true,p_property,&ptr,1); + 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::_remote_call_reliable_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error) { + +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; @@ -604,12 +663,46 @@ Variant Node::_remote_call_reliable_bind(const Variant** p_args, int p_argcount, StringName method = *p_args[0]; - remote_call_reliablep(method,&p_args[1],p_argcount-1); + rpcp(0,true,method,&p_args[1],p_argcount-1); + r_error.error=Variant::CallError::CALL_OK; + return Variant(); } -Variant Node::_remote_call_unreliable_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error) { +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; @@ -626,8 +719,356 @@ Variant Node::_remote_call_unreliable_bind(const Variant** p_args, int p_argcoun StringName method = *p_args[0]; - remote_call_unreliablep(method,&p_args[1],p_argcount-1); + 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; } @@ -2444,11 +2885,9 @@ void Node::_bind_methods() { ObjectTypeDB::bind_method(_MD("is_network_master"),&Node::is_network_master); - ObjectTypeDB::bind_method(_MD("allow_remote_call","method"),&Node::allow_remote_call); - ObjectTypeDB::bind_method(_MD("disallow_remote_call","method"),&Node::disallow_remote_call); + ObjectTypeDB::bind_method(_MD("rpc_config","method","mode"),&Node::rpc_config); + ObjectTypeDB::bind_method(_MD("rset_config","property","mode"),&Node::rset_config); - ObjectTypeDB::bind_method(_MD("allow_remote_set","method"),&Node::allow_remote_set); - ObjectTypeDB::bind_method(_MD("disallow_remote_set","method"),&Node::disallow_remote_set); #ifdef TOOLS_ENABLED ObjectTypeDB::bind_method(_MD("_set_import_path","import_path"),&Node::set_import_path); @@ -2459,19 +2898,29 @@ void Node::_bind_methods() { { MethodInfo mi; - mi.name="remote_call_reliable"; + mi.arguments.push_back( PropertyInfo( Variant::STRING, "method")); - ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"remote_call_reliable",&Node::_remote_call_reliable_bind,mi); + mi.name="rpc"; + ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"rpc",&Node::_rpc_bind,mi); + mi.name="rpc_unreliable"; + ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"rpc_unreliable",&Node::_rpc_unreliable_bind,mi); + + mi.arguments.push_front( PropertyInfo( Variant::INT, "peer_") ); + + mi.name="rpc_id"; + ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"rpc_id",&Node::_rpc_id_bind,mi); + mi.name="rpc_unreliable_id"; + ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"rpc_unreliable_id",&Node::_rpc_unreliable_id_bind,mi); - mi.name="remote_call_unreliable"; - ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"remote_call_unreliable",&Node::_remote_call_unreliable_bind,mi); } - ObjectTypeDB::bind_method(_MD("remote_set_reliable","property","value:Variant"),&Node::remote_set_reliable); - ObjectTypeDB::bind_method(_MD("remote_set_unreliable","property","value:Variant"),&Node::remote_set_unreliable); + 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 ); @@ -2491,7 +2940,15 @@ void Node::_bind_methods() { 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 ); @@ -2506,7 +2963,6 @@ void Node::_bind_methods() { //ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "process/input" ), _SCS("set_process_input"),_SCS("is_processing_input" ) ); //ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "process/unhandled_input" ), _SCS("set_process_unhandled_input"),_SCS("is_processing_unhandled_input" ) ); ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "process/pause_mode",PROPERTY_HINT_ENUM,"Inherit,Stop,Process" ), _SCS("set_pause_mode"),_SCS("get_pause_mode" ) ); - ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "process/network_mode",PROPERTY_HINT_ENUM,"Inherit,Master,Slave" ), _SCS("set_network_mode"),_SCS("get_network_mode" ) ); ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "editor/display_folded",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR ), _SCS("set_display_folded"),_SCS("is_displayed_folded" ) ); BIND_VMETHOD( MethodInfo("_process",PropertyInfo(Variant::REAL,"delta")) ); diff --git a/scene/main/node.h b/scene/main/node.h index 761725286e..3568da2ab0 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -60,6 +60,15 @@ public: 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 { bool operator()(const Node* p_a, const Node* p_b) const { return p_b->is_greater_than(p_a); } @@ -75,6 +84,7 @@ private: }; + struct Data { String filename; @@ -108,8 +118,8 @@ private: NetworkMode network_mode; Node *network_owner; - Set<StringName> allowed_remote_calls; - Set<StringName> allowed_remote_set; + Map<StringName,RPCMode> rpc_methods; + Map<StringName,RPCMode> rpc_properties; // variables used to properly sort the node when processing, ignored otherwise @@ -160,8 +170,10 @@ private: Array _get_children() const; Array _get_groups() const; - Variant _remote_call_reliable_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error); - Variant _remote_call_unreliable_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error); + 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; @@ -358,20 +370,25 @@ public: NetworkMode get_network_mode() const; bool is_network_master() const; - void allow_remote_call(const StringName& p_method); - void disallow_remote_call(const StringName& p_method); + 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 allow_remote_set(const StringName& p_property); - void disallow_remote_set(const StringName& p_property); + void rpcp(int p_peer_id,bool p_unreliable,const StringName& p_method,const Variant** p_arg,int p_argcount); - void remote_call_reliable(const StringName& p_method,VARIANT_ARG_DECLARE); - void remote_call_reliablep(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 remote_call_unreliable(const StringName& p_method,VARIANT_ARG_DECLARE); - void remote_call_unreliablep(const StringName& p_method,const Variant** p_arg,int p_argcount); + void rsetp(int p_peer_id,bool p_unreliable,const StringName& p_property,const Variant& p_value); - void remote_set_reliable(const StringName& p_property,const Variant& p_value); - void remote_set_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(); diff --git a/scene/main/scene_main_loop.cpp b/scene/main/scene_main_loop.cpp index 6af2b9b169..53cc11359a 100644 --- a/scene/main/scene_main_loop.cpp +++ b/scene/main/scene_main_loop.cpp @@ -1657,25 +1657,45 @@ Ref<SceneTreeTimer> SceneTree::create_timer(float p_delay_sec) { return stt; } -void SceneTree::_network_peer_connected(const StringName& p_id) { +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(const StringName& 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(); @@ -1690,6 +1710,9 @@ void SceneTree::set_network_peer(const Ref<NetworkedMultiplayerPeer>& p_network_ 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"); } } @@ -1700,7 +1723,27 @@ bool SceneTree::is_network_server() const { } -void SceneTree::_remote_call(Node* p_from, bool p_reliable, bool p_set, const StringName& p_name, const Variant** p_arg, int p_argcount) { +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."); @@ -1753,11 +1796,17 @@ void SceneTree::_remote_call(Node* p_from, bool p_reliable, bool p_set, const St //see if all peers have cached path (is so, call can be fast) bool has_all_peers=true; - List<StringName> peers_to_add; //if one is missing, take note to add it + 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 - for (Set<StringName>::Element *E=connected_peers.front();E;E=E->next()) { + if (p_to>0 && E->get()!=p_to) + continue; //continue, not for this peer - Map<StringName,bool>::Element *F = psc->confirmed_peers.find(E->get()); + 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 @@ -1773,7 +1822,7 @@ void SceneTree::_remote_call(Node* p_from, bool p_reliable, bool p_set, const St //those that need to be added, send a message for this - for (List<StringName>::Element *E=peers_to_add.front();E;E=E->next()) { + for (List<int>::Element *E=peers_to_add.front();E;E=E->next()) { Array add_path_message; add_path_message.resize(3); @@ -1789,20 +1838,26 @@ void SceneTree::_remote_call(Node* p_from, bool p_reliable, bool p_set, const St } //take chance and set transfer mode, since all send methods will use it - network_peer->set_transfer_mode(p_reliable ? NetworkedMultiplayerPeer::TRANSFER_MODE_ORDERED : NetworkedMultiplayerPeer::TRANSFER_MODE_UNRELIABLE); + network_peer->set_transfer_mode(p_unreliable ? NetworkedMultiplayerPeer::TRANSFER_MODE_UNRELIABLE : NetworkedMultiplayerPeer::TRANSFER_MODE_ORDERED); if (has_all_peers) { //they all have verified paths, so send fast message[1]=psc->id; - network_peer->set_target_peer(StringName()); //to all of you + network_peer->set_target_peer(p_to); //to all of you network_peer->put_var(message); //a message with love } else { //not all verified path, so send one by one - for (Set<StringName>::Element *E=connected_peers.front();E;E=E->next()) { + for (Set<int>::Element *E=connected_peers.front();E;E=E->next()) { - Map<StringName,bool>::Element *F = psc->confirmed_peers.find(E->get()); + 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 @@ -1821,7 +1876,7 @@ void SceneTree::_remote_call(Node* p_from, bool p_reliable, bool p_set, const St } -void SceneTree::_network_process_packet(const StringName& p_from,const Array& p_packet) { +void SceneTree::_network_process_packet(int p_from, const Array& p_packet) { ERR_FAIL_COND(p_packet.empty()); @@ -1847,7 +1902,7 @@ void SceneTree::_network_process_packet(const StringName& p_from,const Array& p_ int id = target; - Map<StringName,PathGetCache>::Element *E=path_get_cache.find(p_from); + 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); @@ -1871,6 +1926,9 @@ void SceneTree::_network_process_packet(const StringName& p_from,const Array& p_ if (packet_type==NETWORK_COMMAND_REMOTE_CALL) { + if (!node->can_call_rpc(name)) + return; + int argc = p_packet.size()-3; Vector<Variant> args; Vector<const Variant*> argp; @@ -1887,11 +1945,15 @@ void SceneTree::_network_process_packet(const StringName& p_from,const Array& p_ 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; + ERR_FAIL_COND(p_packet.size()!=4); Variant value = p_packet[3]; @@ -1938,7 +2000,7 @@ void SceneTree::_network_process_packet(const StringName& p_from,const Array& p_ PathSentCache *psc = path_send_cache.getptr(path); ERR_FAIL_COND(!psc); - Map<StringName,bool>::Element *E=psc->confirmed_peers.find(p_from); + Map<int,bool>::Element *E=psc->confirmed_peers.find(p_from); ERR_FAIL_COND(!E); E->get()=true; } break; @@ -1948,14 +2010,17 @@ void SceneTree::_network_process_packet(const StringName& p_from,const Array& p_ void SceneTree::_network_poll() { - if (!network_peer.is_valid()) + 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()) { - StringName sender = network_peer->get_packet_peer(); + int sender = network_peer->get_packet_peer(); Variant packet; Error err = network_peer->get_var(packet); if (err!=OK) { @@ -1967,6 +2032,10 @@ void SceneTree::_network_poll() { } _network_process_packet(sender,packet); + + if (!network_peer.is_valid()) { + break; //it's also possible that a packet or RPC caused a disconnection, so also check here + } } @@ -2042,9 +2111,15 @@ void SceneTree::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_network_peer","peer:NetworkedMultiplayerPeer"),&SceneTree::set_network_peer); - ObjectTypeDB::bind_method(_MD("is_network_server","is_network_server"),&SceneTree::is_network_server); + 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") ) ); @@ -2055,8 +2130,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::STRING,"id"))); - ADD_SIGNAL( MethodInfo("network_peer_disconnected",PropertyInfo(Variant::STRING,"id"))); + 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 ); diff --git a/scene/main/scene_main_loop.h b/scene/main/scene_main_loop.h index f67dae01be..652a835fd5 100644 --- a/scene/main/scene_main_loop.h +++ b/scene/main/scene_main_loop.h @@ -188,13 +188,17 @@ private: Ref<NetworkedMultiplayerPeer> network_peer; - Set<StringName> connected_peers; - void _network_peer_connected(const StringName& p_id); - void _network_peer_disconnected(const StringName& p_id); + 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<StringName,bool> confirmed_peers; + Map<int,bool> confirmed_peers; int id; }; @@ -211,9 +215,9 @@ private: Map<int,NodeInfo> nodes; }; - Map<StringName,PathGetCache> path_get_cache; + Map<int,PathGetCache> path_get_cache; - void _network_process_packet(const StringName &p_from, const Array& p_packet); + void _network_process_packet(int p_from, const Array& p_packet); void _network_poll(); static SceneTree *singleton; @@ -221,7 +225,8 @@ friend class Node; - void _remote_call(Node* p_from,bool p_reliable,bool p_set,const StringName& p_name,const Variant** p_arg,int p_argcount); + + 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); @@ -418,6 +423,10 @@ public: 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(); |