diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp index b0f2ca754d0..846c89510ee 100644 --- a/core/io/multiplayer_api.cpp +++ b/core/io/multiplayer_api.cpp @@ -32,6 +32,61 @@ #include "core/io/marshalls.h" #include "scene/main/node.h" +_FORCE_INLINE_ bool _should_call_local(MultiplayerAPI::RPCMode mode, bool is_master, bool &r_skip_rpc) { + + switch (mode) { + + case MultiplayerAPI::RPC_MODE_DISABLED: { + //do nothing + } break; + case MultiplayerAPI::RPC_MODE_REMOTE: { + //do nothing also, no need to call local + } break; + case MultiplayerAPI::RPC_MODE_REMOTESYNC: + case MultiplayerAPI::RPC_MODE_MASTERSYNC: + case MultiplayerAPI::RPC_MODE_SLAVESYNC: + case MultiplayerAPI::RPC_MODE_SYNC: { + //call it, sync always results in call + return true; + } break; + case MultiplayerAPI::RPC_MODE_MASTER: { + if (is_master) + r_skip_rpc = true; //no other master so.. + return is_master; + } break; + case MultiplayerAPI::RPC_MODE_SLAVE: { + return !is_master; + } break; + } + return false; +} + +_FORCE_INLINE_ bool _can_call_mode(Node *p_node, MultiplayerAPI::RPCMode mode, int p_remote_id) { + switch (mode) { + + case MultiplayerAPI::RPC_MODE_DISABLED: { + return false; + } break; + case MultiplayerAPI::RPC_MODE_REMOTE: { + return true; + } break; + case MultiplayerAPI::RPC_MODE_REMOTESYNC: + case MultiplayerAPI::RPC_MODE_SYNC: { + return true; + } break; + case MultiplayerAPI::RPC_MODE_MASTERSYNC: + case MultiplayerAPI::RPC_MODE_MASTER: { + return p_node->is_network_master(); + } break; + case MultiplayerAPI::RPC_MODE_SLAVESYNC: + case MultiplayerAPI::RPC_MODE_SLAVE: { + return !p_node->is_network_master() && p_remote_id == p_node->get_network_master(); + } break; + } + + return false; +} + void MultiplayerAPI::poll() { if (!network_peer.is_valid() || network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED) @@ -202,11 +257,19 @@ Node *MultiplayerAPI::_process_get_node(int p_from, const uint8_t *p_packet, int } void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset) { - if (!p_node->can_call_rpc(p_name, p_from)) - return; ERR_FAIL_COND(p_offset >= p_packet_len); + // Check that remote can call the RPC on this node + RPCMode rpc_mode = RPC_MODE_DISABLED; + const Map::Element *E = p_node->get_node_rpc_mode(p_name); + if (E) { + rpc_mode = E->get(); + } else if (p_node->get_script_instance()) { + rpc_mode = p_node->get_script_instance()->get_rpc_mode(p_name); + } + ERR_FAIL_COND(!_can_call_mode(p_node, rpc_mode, p_from)); + int argc = p_packet[p_offset]; Vector args; Vector argp; @@ -238,11 +301,18 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_ void MultiplayerAPI::_process_rset(Node *p_node, const StringName &p_name, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset) { - if (!p_node->can_call_rset(p_name, p_from)) - return; - ERR_FAIL_COND(p_offset >= p_packet_len); + // Check that remote can call the RSET on this node + RPCMode rset_mode = RPC_MODE_DISABLED; + const Map::Element *E = p_node->get_node_rset_mode(p_name); + if (E) { + rset_mode = E->get(); + } else if (p_node->get_script_instance()) { + rset_mode = p_node->get_script_instance()->get_rset_mode(p_name); + } + ERR_FAIL_COND(!_can_call_mode(p_node, rset_mode, p_from)); + Variant value; decode_variant(value, &p_packet[p_offset], p_packet_len - p_offset); @@ -522,57 +592,6 @@ void MultiplayerAPI::_server_disconnected() { emit_signal("server_disconnected"); } -bool _should_call_native(Node::RPCMode mode, bool is_master, bool &r_skip_rpc) { - - switch (mode) { - - case Node::RPC_MODE_DISABLED: { - //do nothing - } break; - case Node::RPC_MODE_REMOTE: { - //do nothing also, no need to call local - } break; - case Node::RPC_MODE_SYNC: { - //call it, sync always results in call - return true; - } break; - case Node::RPC_MODE_MASTER: { - if (is_master) - r_skip_rpc = true; //no other master so.. - return is_master; - } break; - case Node::RPC_MODE_SLAVE: { - return !is_master; - } break; - } - return false; -} - -bool _should_call_script(ScriptInstance::RPCMode mode, bool is_master, bool &r_skip_rpc) { - switch (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 - return true; - } break; - case ScriptInstance::RPC_MODE_MASTER: { - if (is_master) - r_skip_rpc = true; //no other master so.. - return is_master; - } break; - case ScriptInstance::RPC_MODE_SLAVE: { - return !is_master; - } break; - } - return false; -} - void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount) { ERR_FAIL_COND(!p_node->is_inside_tree()); @@ -587,17 +606,17 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const if (p_peer_id == 0 || p_peer_id == node_id || (p_peer_id < 0 && p_peer_id != -node_id)) { //check that send mode can use local call - const Map::Element *E = p_node->get_node_rpc_mode(p_method); + const Map::Element *E = p_node->get_node_rpc_mode(p_method); if (E) { - call_local_native = _should_call_native(E->get(), is_master, skip_rpc); + call_local_native = _should_call_local(E->get(), is_master, skip_rpc); } if (call_local_native) { // done below } else if (p_node->get_script_instance()) { //attempt with script - ScriptInstance::RPCMode rpc_mode = p_node->get_script_instance()->get_rpc_mode(p_method); - call_local_script = _should_call_script(rpc_mode, is_master, skip_rpc); + RPCMode rpc_mode = p_node->get_script_instance()->get_rpc_mode(p_method); + call_local_script = _should_call_local(rpc_mode, is_master, skip_rpc); } } @@ -643,10 +662,10 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const bool set_local = false; - const Map::Element *E = p_node->get_node_rset_mode(p_property); + const Map::Element *E = p_node->get_node_rset_mode(p_property); if (E) { - set_local = _should_call_native(E->get(), is_master, skip_rset); + set_local = _should_call_local(E->get(), is_master, skip_rset); } if (set_local) { @@ -660,9 +679,9 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const } } else if (p_node->get_script_instance()) { //attempt with script - ScriptInstance::RPCMode rpc_mode = p_node->get_script_instance()->get_rset_mode(p_property); + RPCMode rpc_mode = p_node->get_script_instance()->get_rset_mode(p_property); - set_local = _should_call_script(rpc_mode, is_master, skip_rset); + set_local = _should_call_local(rpc_mode, is_master, skip_rset); if (set_local) { @@ -778,6 +797,15 @@ void MultiplayerAPI::_bind_methods() { ADD_SIGNAL(MethodInfo("connected_to_server")); ADD_SIGNAL(MethodInfo("connection_failed")); ADD_SIGNAL(MethodInfo("server_disconnected")); + + BIND_ENUM_CONSTANT(RPC_MODE_DISABLED); + BIND_ENUM_CONSTANT(RPC_MODE_REMOTE); + BIND_ENUM_CONSTANT(RPC_MODE_SYNC); + BIND_ENUM_CONSTANT(RPC_MODE_MASTER); + BIND_ENUM_CONSTANT(RPC_MODE_SLAVE); + BIND_ENUM_CONSTANT(RPC_MODE_REMOTESYNC); + BIND_ENUM_CONSTANT(RPC_MODE_MASTERSYNC); + BIND_ENUM_CONSTANT(RPC_MODE_SLAVESYNC); } MultiplayerAPI::MultiplayerAPI() { diff --git a/core/io/multiplayer_api.h b/core/io/multiplayer_api.h index 64f59d32d84..ef56c4c7f29 100644 --- a/core/io/multiplayer_api.h +++ b/core/io/multiplayer_api.h @@ -87,6 +87,18 @@ public: NETWORK_COMMAND_RAW, }; + 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 remote peers + RPC_MODE_SYNC, // Using rpc() on it will call method / set property in all remote peers and locally + RPC_MODE_MASTER, // Using rpc() on it will call method on wherever the master is, be it local or remote + RPC_MODE_SLAVE, // Using rpc() on it will call method for all slaves + RPC_MODE_REMOTESYNC, // Same as RPC_MODE_SYNC, compatibility + RPC_MODE_MASTERSYNC, // Using rpc() on it will call method / set property in the master peer and locally + RPC_MODE_SLAVESYNC, // Using rpc() on it will call method / set property in all slave peers and locally + }; + void poll(); void clear(); void set_root_node(Node *p_node); @@ -117,4 +129,6 @@ public: ~MultiplayerAPI(); }; +VARIANT_ENUM_CAST(MultiplayerAPI::RPCMode); + #endif // MULTIPLAYER_PROTOCOL_H diff --git a/core/script_language.h b/core/script_language.h index b4c55cac9e5..ad66fc55283 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -31,6 +31,7 @@ #ifndef SCRIPT_LANGUAGE_H #define SCRIPT_LANGUAGE_H +#include "io/multiplayer_api.h" #include "map.h" #include "pair.h" #include "resource.h" @@ -157,16 +158,8 @@ public: virtual bool is_placeholder() const { return false; } - enum RPCMode { - RPC_MODE_DISABLED, - RPC_MODE_REMOTE, - RPC_MODE_SYNC, - RPC_MODE_MASTER, - RPC_MODE_SLAVE, - }; - - virtual RPCMode get_rpc_mode(const StringName &p_method) const = 0; - virtual RPCMode get_rset_mode(const StringName &p_variable) const = 0; + virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const = 0; + virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const = 0; virtual ScriptLanguage *get_language() = 0; virtual ~ScriptInstance(); @@ -332,8 +325,8 @@ public: virtual bool is_placeholder() const { return true; } - virtual RPCMode get_rpc_mode(const StringName &p_method) const { return RPC_MODE_DISABLED; } - virtual RPCMode get_rset_mode(const StringName &p_variable) const { return RPC_MODE_DISABLED; } + virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const { return MultiplayerAPI::RPC_MODE_DISABLED; } + virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const { return MultiplayerAPI::RPC_MODE_DISABLED; } PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref