[MP] RPC visibility.
Implemented using MultiplayerSynchronizers. If you didn't use the synchronizer visibility features, nothing changes. If you were using visibility, RPCs to broadcast should now behave as expected in most configurations (i.e. by sending the RPC to _visible_ peers). If you want to limit the visibility of RPCs for a node, add a synchronizer for it, and configure the visibility via "set_visibility_for" or by adding a visibility filter.
This commit is contained in:
@ -295,7 +295,7 @@ void SceneRPCInterface::_process_rpc(Node *p_node, const uint16_t p_rpc_method_i
|
||||
}
|
||||
}
|
||||
|
||||
void SceneRPCInterface::_send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, const RPCConfig &p_config, const StringName &p_name, const Variant **p_arg, int p_argcount) {
|
||||
void SceneRPCInterface::_send_rpc(Node *p_node, int p_to, uint16_t p_rpc_id, const RPCConfig &p_config, const StringName &p_name, const Variant **p_arg, int p_argcount) {
|
||||
Ref<MultiplayerPeer> peer = multiplayer->get_multiplayer_peer();
|
||||
ERR_FAIL_COND_MSG(peer.is_null(), "Attempt to call RPC without active multiplayer peer.");
|
||||
|
||||
@ -311,12 +311,35 @@ void SceneRPCInterface::_send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, con
|
||||
ERR_FAIL_MSG("Attempt to call RPC with unknown peer ID: " + itos(p_to) + ".");
|
||||
}
|
||||
|
||||
// See if all peers have cached path (if so, call can be fast).
|
||||
int psc_id;
|
||||
const bool has_all_peers = multiplayer->get_path_cache()->send_object_cache(p_from, p_to, psc_id);
|
||||
// See if all peers have cached path (if so, call can be fast) while building the RPC target list.
|
||||
HashSet<int> targets;
|
||||
Ref<SceneCacheInterface> cache = multiplayer->get_path_cache();
|
||||
int psc_id = -1;
|
||||
bool has_all_peers = true;
|
||||
const ObjectID oid = p_node->get_instance_id();
|
||||
if (p_to > 0) {
|
||||
ERR_FAIL_COND_MSG(!multiplayer->get_replicator()->is_rpc_visible(oid, p_to), "Attempt to call an RPC to a peer that cannot see this node. Peer ID: " + itos(p_to));
|
||||
targets.insert(p_to);
|
||||
has_all_peers = cache->send_object_cache(p_node, p_to, psc_id);
|
||||
} else {
|
||||
bool restricted = !multiplayer->get_replicator()->is_rpc_visible(oid, 0);
|
||||
for (const int &P : multiplayer->get_connected_peers()) {
|
||||
if (p_to < 0 && P == -p_to) {
|
||||
continue; // Excluded peer.
|
||||
}
|
||||
if (restricted && !multiplayer->get_replicator()->is_rpc_visible(oid, P)) {
|
||||
continue; // Not visible to this peer.
|
||||
}
|
||||
targets.insert(P);
|
||||
bool has_peer = cache->send_object_cache(p_node, P, psc_id);
|
||||
has_all_peers = has_all_peers && has_peer;
|
||||
}
|
||||
}
|
||||
if (targets.is_empty()) {
|
||||
return; // No one in sight.
|
||||
}
|
||||
|
||||
// Create base packet, lots of hardcode because it must be tight.
|
||||
|
||||
int ofs = 0;
|
||||
|
||||
#define MAKE_ROOM(m_amount) \
|
||||
@ -399,7 +422,7 @@ void SceneRPCInterface::_send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, con
|
||||
ERR_FAIL_COND(name_id_compression > 1);
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
_profile_node_data("rpc_out", p_from->get_instance_id(), ofs);
|
||||
_profile_node_data("rpc_out", p_node->get_instance_id(), ofs);
|
||||
#endif
|
||||
|
||||
// We can now set the meta
|
||||
@ -410,8 +433,9 @@ void SceneRPCInterface::_send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, con
|
||||
peer->set_transfer_mode(p_config.transfer_mode);
|
||||
|
||||
if (has_all_peers) {
|
||||
// They all have verified paths, so send fast.
|
||||
multiplayer->send_command(p_to, packet_cache.ptr(), ofs);
|
||||
for (const int P : targets) {
|
||||
multiplayer->send_command(P, packet_cache.ptr(), ofs);
|
||||
}
|
||||
} else {
|
||||
// Unreachable because the node ID is never compressed if the peers doesn't know it.
|
||||
CRASH_COND(node_id_compression != NETWORK_NODE_ID_COMPRESSION_32);
|
||||
@ -419,23 +443,15 @@ void SceneRPCInterface::_send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, con
|
||||
// Not all verified path, so send one by one.
|
||||
|
||||
// Append path at the end, since we will need it for some packets.
|
||||
NodePath from_path = multiplayer->get_root_path().rel_path_to(p_from->get_path());
|
||||
NodePath from_path = multiplayer->get_root_path().rel_path_to(p_node->get_path());
|
||||
CharString pname = String(from_path).utf8();
|
||||
int path_len = encode_cstring(pname.get_data(), nullptr);
|
||||
MAKE_ROOM(ofs + path_len);
|
||||
encode_cstring(pname.get_data(), &(packet_cache.write[ofs]));
|
||||
|
||||
for (const int &P : multiplayer->get_connected_peers()) {
|
||||
if (p_to < 0 && P == -p_to) {
|
||||
continue; // Continue, excluded.
|
||||
}
|
||||
|
||||
if (p_to > 0 && P != p_to) {
|
||||
continue; // Continue, not for this peer.
|
||||
}
|
||||
|
||||
// Not all verified path, so check which needs the longer packet.
|
||||
for (const int P : targets) {
|
||||
bool confirmed = multiplayer->get_path_cache()->is_cache_confirmed(from_path, P);
|
||||
|
||||
if (confirmed) {
|
||||
// This one confirmed path, so use id.
|
||||
encode_uint32(psc_id, &(packet_cache.write[1]));
|
||||
|
||||
Reference in New Issue
Block a user