summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/main/node.cpp556
-rw-r--r--scene/main/node.h45
-rw-r--r--scene/main/scene_main_loop.cpp116
-rw-r--r--scene/main/scene_main_loop.h23
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();