diff options
author | Fabio Alessandrelli <fabio.alessandrelli@gmail.com> | 2023-09-26 20:27:53 +0200 |
---|---|---|
committer | Fabio Alessandrelli <fabio.alessandrelli@gmail.com> | 2023-10-10 14:42:48 +0200 |
commit | 61cf7d180cc6ac1be1f9cb1c7369b2cae5d99b25 (patch) | |
tree | b1d4d6ad7d8bc3ca6f6d3e81f06867f9ddf862db | |
parent | d80ce0c52a097c35bb4d441e7a9c0a76e6342ba4 (diff) | |
download | redot-engine-61cf7d180cc6ac1be1f9cb1c7369b2cae5d99b25.tar.gz |
[MP] Optimize multiplayer NodePath caching
Only use paths during network transfer.
Use ObjectID instead of NodePaths for storing the Node <-> NetID
relations locally.
-rw-r--r-- | modules/multiplayer/scene_cache_interface.cpp | 52 | ||||
-rw-r--r-- | modules/multiplayer/scene_cache_interface.h | 6 | ||||
-rw-r--r-- | modules/multiplayer/scene_rpc_interface.cpp | 5 |
3 files changed, 36 insertions, 27 deletions
diff --git a/modules/multiplayer/scene_cache_interface.cpp b/modules/multiplayer/scene_cache_interface.cpp index 8d102ca981..56cd0bec18 100644 --- a/modules/multiplayer/scene_cache_interface.cpp +++ b/modules/multiplayer/scene_cache_interface.cpp @@ -44,9 +44,8 @@ void SceneCacheInterface::on_peer_change(int p_id, bool p_connected) { path_get_cache.erase(p_id); // Cleanup sent cache. // Some refactoring is needed to make this faster and do paths GC. - for (const KeyValue<NodePath, PathSentCache> &E : path_send_cache) { - PathSentCache *psc = path_send_cache.getptr(E.key); - psc->confirmed_peers.erase(p_id); + for (KeyValue<ObjectID, PathSentCache> &E : path_send_cache) { + E.value.confirmed_peers.erase(p_id); } } } @@ -67,7 +66,7 @@ void SceneCacheInterface::process_simplify_path(int p_from, const uint8_t *p_pac String paths; paths.parse_utf8((const char *)(p_packet + ofs), p_packet_len - ofs); - NodePath path = paths; + const NodePath path = paths; if (!path_get_cache.has(p_from)) { path_get_cache[p_from] = PathGetCache(); @@ -81,7 +80,7 @@ void SceneCacheInterface::process_simplify_path(int p_from, const uint8_t *p_pac } PathGetCache::NodeInfo ni; - ni.path = path; + ni.path = node->get_path(); path_get_cache[p_from].nodes[id] = ni; @@ -106,19 +105,24 @@ void SceneCacheInterface::process_simplify_path(int p_from, const uint8_t *p_pac void SceneCacheInterface::process_confirm_path(int p_from, const uint8_t *p_packet, int p_packet_len) { ERR_FAIL_COND_MSG(p_packet_len < 3, "Invalid packet received. Size too small."); + Node *root_node = SceneTree::get_singleton()->get_root()->get_node(multiplayer->get_root_path()); + ERR_FAIL_NULL(root_node); const bool valid_rpc_checksum = p_packet[1]; String paths; paths.parse_utf8((const char *)&p_packet[2], p_packet_len - 2); - NodePath path = paths; + const NodePath path = paths; if (valid_rpc_checksum == false) { ERR_PRINT("The rpc node checksum failed. Make sure to have the same methods on both nodes. Node path: " + path); } - PathSentCache *psc = path_send_cache.getptr(path); + Node *node = root_node->get_node(path); + ERR_FAIL_NULL(node); + + PathSentCache *psc = path_send_cache.getptr(node->get_instance_id()); ERR_FAIL_NULL_MSG(psc, "Invalid packet received. Tries to confirm a path which was not found in cache."); HashMap<int, bool>::Iterator E = psc->confirmed_peers.find(p_from); @@ -126,9 +130,9 @@ void SceneCacheInterface::process_confirm_path(int p_from, const uint8_t *p_pack E->value = true; } -Error SceneCacheInterface::_send_confirm_path(Node *p_node, NodePath p_path, PathSentCache *psc, const List<int> &p_peers) { +Error SceneCacheInterface::_send_confirm_path(Node *p_node, PathSentCache *psc, const List<int> &p_peers) { // Encode function name. - const CharString path = String(p_path).utf8(); + const CharString path = String(multiplayer->get_root_path().rel_path_to(p_node->get_path())).utf8(); const int path_len = encode_cstring(path.get_data(), nullptr); // Extract MD5 from rpc methods list. @@ -163,8 +167,9 @@ Error SceneCacheInterface::_send_confirm_path(Node *p_node, NodePath p_path, Pat return err; } -bool SceneCacheInterface::is_cache_confirmed(NodePath p_path, int p_peer) { - const PathSentCache *psc = path_send_cache.getptr(p_path); +bool SceneCacheInterface::is_cache_confirmed(Node *p_node, int p_peer) { + ERR_FAIL_NULL_V(p_node, false); + const PathSentCache *psc = path_send_cache.getptr(p_node->get_instance_id()); ERR_FAIL_NULL_V(psc, false); HashMap<int, bool>::ConstIterator F = psc->confirmed_peers.find(p_peer); ERR_FAIL_COND_V(!F, false); // Should never happen. @@ -174,13 +179,13 @@ bool SceneCacheInterface::is_cache_confirmed(NodePath p_path, int p_peer) { int SceneCacheInterface::make_object_cache(Object *p_obj) { Node *node = Object::cast_to<Node>(p_obj); ERR_FAIL_NULL_V(node, -1); - NodePath for_path = multiplayer->get_root_path().rel_path_to(node->get_path()); + const ObjectID oid = node->get_instance_id(); // See if the path is cached. - PathSentCache *psc = path_send_cache.getptr(for_path); + PathSentCache *psc = path_send_cache.getptr(oid); if (!psc) { // Path is not cached, create. - path_send_cache[for_path] = PathSentCache(); - psc = path_send_cache.getptr(for_path); + path_send_cache[oid] = PathSentCache(); + psc = path_send_cache.getptr(oid); psc->id = last_send_cache_id++; } return psc->id; @@ -189,11 +194,16 @@ int SceneCacheInterface::make_object_cache(Object *p_obj) { bool SceneCacheInterface::send_object_cache(Object *p_obj, int p_peer_id, int &r_id) { Node *node = Object::cast_to<Node>(p_obj); ERR_FAIL_NULL_V(node, false); - - r_id = make_object_cache(p_obj); - ERR_FAIL_COND_V(r_id < 0, false); - NodePath for_path = multiplayer->get_root_path().rel_path_to(node->get_path()); - PathSentCache *psc = path_send_cache.getptr(for_path); + const ObjectID oid = node->get_instance_id(); + // See if the path is cached. + PathSentCache *psc = path_send_cache.getptr(oid); + if (!psc) { + // Path is not cached, create. + path_send_cache[oid] = PathSentCache(); + psc = path_send_cache.getptr(oid); + psc->id = last_send_cache_id++; + } + r_id = psc->id; bool has_all_peers = true; List<int> peers_to_add; // If one is missing, take note to add it. @@ -225,7 +235,7 @@ bool SceneCacheInterface::send_object_cache(Object *p_obj, int p_peer_id, int &r } if (peers_to_add.size()) { - _send_confirm_path(node, for_path, psc, peers_to_add); + _send_confirm_path(node, psc, peers_to_add); } return has_all_peers; diff --git a/modules/multiplayer/scene_cache_interface.h b/modules/multiplayer/scene_cache_interface.h index 7a7304fde8..e63beb5f84 100644 --- a/modules/multiplayer/scene_cache_interface.h +++ b/modules/multiplayer/scene_cache_interface.h @@ -58,12 +58,12 @@ private: HashMap<int, NodeInfo> nodes; }; - HashMap<NodePath, PathSentCache> path_send_cache; + HashMap<ObjectID, PathSentCache> path_send_cache; HashMap<int, PathGetCache> path_get_cache; int last_send_cache_id = 1; protected: - Error _send_confirm_path(Node *p_node, NodePath p_path, PathSentCache *psc, const List<int> &p_peers); + Error _send_confirm_path(Node *p_node, PathSentCache *psc, const List<int> &p_peers); public: void clear(); @@ -75,7 +75,7 @@ public: bool send_object_cache(Object *p_obj, int p_target, int &p_id); int make_object_cache(Object *p_obj); Object *get_cached_object(int p_from, uint32_t p_cache_id); - bool is_cache_confirmed(NodePath p_path, int p_peer); + bool is_cache_confirmed(Node *p_path, int p_peer); SceneCacheInterface(SceneMultiplayer *p_multiplayer) { multiplayer = p_multiplayer; } }; diff --git a/modules/multiplayer/scene_rpc_interface.cpp b/modules/multiplayer/scene_rpc_interface.cpp index 48e1d13f9c..bf0a261bd8 100644 --- a/modules/multiplayer/scene_rpc_interface.cpp +++ b/modules/multiplayer/scene_rpc_interface.cpp @@ -443,15 +443,14 @@ void SceneRPCInterface::_send_rpc(Node *p_node, 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_node->get_path()); - CharString pname = String(from_path).utf8(); + CharString pname = String(multiplayer->get_root_path().rel_path_to(p_node->get_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])); // 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); + bool confirmed = multiplayer->get_path_cache()->is_cache_confirmed(p_node, P); if (confirmed) { // This one confirmed path, so use id. encode_uint32(psc_id, &(packet_cache.write[1])); |