Skip to content

Commit

Permalink
[MP] Partially revert cache cleanup, track paths as fallback
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Faless committed Jul 31, 2024
1 parent 0e9caa2 commit 90d5d26
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 10 deletions.
31 changes: 22 additions & 9 deletions modules/multiplayer/scene_cache_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,14 @@ void SceneCacheInterface::_remove_node_cache(ObjectID p_oid) {
if (nc->cache_id) {
assigned_ids.erase(nc->cache_id);
}
#if 0
// TODO: Find a way to cleanup recv_nodes without breaking visibility and RPCs interactions.
for (KeyValue<int, int> &E : nc->recv_ids) {
PeerInfo *pinfo = peers_info.getptr(E.key);
ERR_CONTINUE(!pinfo);
pinfo->recv_nodes.erase(E.value);
}
#endif
for (KeyValue<int, bool> &E : nc->confirmed_peers) {
PeerInfo *pinfo = peers_info.getptr(E.key);
ERR_CONTINUE(!pinfo);
Expand All @@ -73,9 +76,12 @@ void SceneCacheInterface::on_peer_change(int p_id, bool p_connected) {
} else {
PeerInfo *pinfo = peers_info.getptr(p_id);
ERR_FAIL_NULL(pinfo); // Bug.
for (KeyValue<int, ObjectID> E : pinfo->recv_nodes) {
NodeCache *nc = nodes_cache.getptr(E.value);
ERR_CONTINUE(!nc);
for (KeyValue<int, RecvNode> E : pinfo->recv_nodes) {
NodeCache *nc = nodes_cache.getptr(E.value.oid);
if (!nc) {
// Node might have already been deleted locally.
continue;
}
nc->recv_ids.erase(p_id);
}
for (const ObjectID &oid : pinfo->sent_nodes) {
Expand Down Expand Up @@ -115,7 +121,7 @@ void SceneCacheInterface::process_simplify_path(int p_from, const uint8_t *p_pac
ERR_PRINT("The rpc node checksum failed. Make sure to have the same methods on both nodes. Node path: " + path);
}

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

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

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

const ObjectID *oid = pinfo->recv_nodes.getptr(p_cache_id);
ERR_FAIL_NULL_V_MSG(oid, nullptr, vformat("ID %d not found in cache of peer %d.", p_cache_id, p_from));
Node *node = Object::cast_to<Node>(ObjectDB::get_instance(*oid));
RecvNode *recv_node = pinfo->recv_nodes.getptr(p_cache_id);
ERR_FAIL_NULL_V_MSG(recv_node, nullptr, vformat("ID %d not found in cache of peer %d.", p_cache_id, p_from));
Node *node = Object::cast_to<Node>(ObjectDB::get_instance(recv_node->oid));
if (!node) {
// Fallback to path lookup.
Node *root_node = SceneTree::get_singleton()->get_root()->get_node(multiplayer->get_root_path());
ERR_FAIL_NULL_V(root_node, nullptr);
node = root_node->get_node(recv_node->path);
if (node) {
recv_node->oid = node->get_instance_id();
}
}
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));
return node;
}
Expand Down
12 changes: 11 additions & 1 deletion modules/multiplayer/scene_cache_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,18 @@ class SceneCacheInterface : public RefCounted {
HashMap<int, bool> confirmed_peers; // peer id, confirmed
};

struct RecvNode {
ObjectID oid;
NodePath path;

RecvNode(const ObjectID &p_oid, const NodePath &p_path) {
oid = p_oid;
path = p_path;
}
};

struct PeerInfo {
HashMap<int, ObjectID> recv_nodes; // remote cache id, ObjectID
HashMap<int, RecvNode> recv_nodes; // remote cache id, (ObjectID, NodePath)
HashSet<ObjectID> sent_nodes;
};

Expand Down

0 comments on commit 90d5d26

Please sign in to comment.