Skip to content

Commit 90d5d26

Browse files
committed
[MP] Partially revert cache cleanup, track paths as fallback
Cleaning up remote NodePath cache is not trivial since the visibility API allows for certain nodes to be despawned (and re-spawned) on some peers while being retained in the authority. This means that from the server point of view, the node has not changed, and the path simplification protocol won't be run again after respawning. While we can track this information for synchronizers via the replication API, we can't easily track this information for potential child nodes that use RPCs (I'm convinced it is doable, but we need to track the whole dependency tree which would require some more complex refactoring). This commit partially reverts some of the cache cleanup logic to always retain remote IDs, and adds a NodePath lookup fallback when the ObjectID is invalid.
1 parent 0e9caa2 commit 90d5d26

File tree

2 files changed

+33
-10
lines changed

2 files changed

+33
-10
lines changed

modules/multiplayer/scene_cache_interface.cpp

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,14 @@ void SceneCacheInterface::_remove_node_cache(ObjectID p_oid) {
5454
if (nc->cache_id) {
5555
assigned_ids.erase(nc->cache_id);
5656
}
57+
#if 0
58+
// TODO: Find a way to cleanup recv_nodes without breaking visibility and RPCs interactions.
5759
for (KeyValue<int, int> &E : nc->recv_ids) {
5860
PeerInfo *pinfo = peers_info.getptr(E.key);
5961
ERR_CONTINUE(!pinfo);
6062
pinfo->recv_nodes.erase(E.value);
6163
}
64+
#endif
6265
for (KeyValue<int, bool> &E : nc->confirmed_peers) {
6366
PeerInfo *pinfo = peers_info.getptr(E.key);
6467
ERR_CONTINUE(!pinfo);
@@ -73,9 +76,12 @@ void SceneCacheInterface::on_peer_change(int p_id, bool p_connected) {
7376
} else {
7477
PeerInfo *pinfo = peers_info.getptr(p_id);
7578
ERR_FAIL_NULL(pinfo); // Bug.
76-
for (KeyValue<int, ObjectID> E : pinfo->recv_nodes) {
77-
NodeCache *nc = nodes_cache.getptr(E.value);
78-
ERR_CONTINUE(!nc);
79+
for (KeyValue<int, RecvNode> E : pinfo->recv_nodes) {
80+
NodeCache *nc = nodes_cache.getptr(E.value.oid);
81+
if (!nc) {
82+
// Node might have already been deleted locally.
83+
continue;
84+
}
7985
nc->recv_ids.erase(p_id);
8086
}
8187
for (const ObjectID &oid : pinfo->sent_nodes) {
@@ -115,7 +121,7 @@ void SceneCacheInterface::process_simplify_path(int p_from, const uint8_t *p_pac
115121
ERR_PRINT("The rpc node checksum failed. Make sure to have the same methods on both nodes. Node path: " + path);
116122
}
117123

118-
peers_info[p_from].recv_nodes.insert(id, node->get_instance_id());
124+
peers_info[p_from].recv_nodes.insert(id, RecvNode(node->get_instance_id(), path));
119125
NodeCache &cache = _track(node);
120126
cache.recv_ids.insert(p_from, id);
121127

@@ -269,14 +275,21 @@ bool SceneCacheInterface::send_object_cache(Object *p_obj, int p_peer_id, int &r
269275
}
270276

271277
Object *SceneCacheInterface::get_cached_object(int p_from, uint32_t p_cache_id) {
272-
Node *root_node = SceneTree::get_singleton()->get_root()->get_node(multiplayer->get_root_path());
273-
ERR_FAIL_NULL_V(root_node, nullptr);
274278
PeerInfo *pinfo = peers_info.getptr(p_from);
275279
ERR_FAIL_NULL_V(pinfo, nullptr);
276280

277-
const ObjectID *oid = pinfo->recv_nodes.getptr(p_cache_id);
278-
ERR_FAIL_NULL_V_MSG(oid, nullptr, vformat("ID %d not found in cache of peer %d.", p_cache_id, p_from));
279-
Node *node = Object::cast_to<Node>(ObjectDB::get_instance(*oid));
281+
RecvNode *recv_node = pinfo->recv_nodes.getptr(p_cache_id);
282+
ERR_FAIL_NULL_V_MSG(recv_node, nullptr, vformat("ID %d not found in cache of peer %d.", p_cache_id, p_from));
283+
Node *node = Object::cast_to<Node>(ObjectDB::get_instance(recv_node->oid));
284+
if (!node) {
285+
// Fallback to path lookup.
286+
Node *root_node = SceneTree::get_singleton()->get_root()->get_node(multiplayer->get_root_path());
287+
ERR_FAIL_NULL_V(root_node, nullptr);
288+
node = root_node->get_node(recv_node->path);
289+
if (node) {
290+
recv_node->oid = node->get_instance_id();
291+
}
292+
}
280293
ERR_FAIL_NULL_V_MSG(node, nullptr, vformat("Failed to get cached node from peer %d with cache ID %d.", p_from, p_cache_id));
281294
return node;
282295
}

modules/multiplayer/scene_cache_interface.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,18 @@ class SceneCacheInterface : public RefCounted {
4949
HashMap<int, bool> confirmed_peers; // peer id, confirmed
5050
};
5151

52+
struct RecvNode {
53+
ObjectID oid;
54+
NodePath path;
55+
56+
RecvNode(const ObjectID &p_oid, const NodePath &p_path) {
57+
oid = p_oid;
58+
path = p_path;
59+
}
60+
};
61+
5262
struct PeerInfo {
53-
HashMap<int, ObjectID> recv_nodes; // remote cache id, ObjectID
63+
HashMap<int, RecvNode> recv_nodes; // remote cache id, (ObjectID, NodePath)
5464
HashSet<ObjectID> sent_nodes;
5565
};
5666

0 commit comments

Comments
 (0)