From 32e4ab91e8d1b266990ca98b5ec1ead19a1a1dd5 Mon Sep 17 00:00:00 2001 From: Fabio Alessandrelli Date: Thu, 12 Sep 2024 16:38:14 +0200 Subject: [PATCH] [MP] Fix broken RPCs after dictionary keys type change As part of RPCs processing, they need to be sorted reliably across all peers, so that unique IDs can be assigned to greatly optimize the network layer. The RPC configuration nodes are stored in dictionaries which, until recently, always casted StringName keys to String. Since method names (keys) in the RPC configuration were StringName, a side effect of the above change is that sorting the dictionary keys no longer sort them alphabetically by default (StringName are compared using their pointers). This commit changes the RPC processing logic to use sort_custom to provide a function that can handle the StringName comparison. --- modules/multiplayer/scene_rpc_interface.cpp | 12 +++++++++++- modules/multiplayer/scene_rpc_interface.h | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/modules/multiplayer/scene_rpc_interface.cpp b/modules/multiplayer/scene_rpc_interface.cpp index 592bb18a710..69bb19c01c4 100644 --- a/modules/multiplayer/scene_rpc_interface.cpp +++ b/modules/multiplayer/scene_rpc_interface.cpp @@ -73,6 +73,16 @@ int get_packet_len(uint32_t p_node_target, int p_packet_len) { } } +bool SceneRPCInterface::_sort_rpc_names(const Variant &p_l, const Variant &p_r) { + if (likely(p_l.is_string() && p_r.is_string())) { + return p_l.operator String() < p_r.operator String(); + } + bool valid = false; + Variant res; + Variant::evaluate(Variant::OP_LESS, p_l, p_r, res, valid); + return valid ? res.operator bool() : false; +} + void SceneRPCInterface::_parse_rpc_config(const Variant &p_config, bool p_for_node, RPCConfigCache &r_cache) { if (p_config.get_type() == Variant::NIL) { return; @@ -80,7 +90,7 @@ void SceneRPCInterface::_parse_rpc_config(const Variant &p_config, bool p_for_no ERR_FAIL_COND(p_config.get_type() != Variant::DICTIONARY); const Dictionary config = p_config; Array names = config.keys(); - names.sort(); // Ensure ID order + names.sort_custom(callable_mp_static(&SceneRPCInterface::_sort_rpc_names)); // Ensure ID order for (int i = 0; i < names.size(); i++) { ERR_CONTINUE(!names[i].is_string()); String name = names[i].operator String(); diff --git a/modules/multiplayer/scene_rpc_interface.h b/modules/multiplayer/scene_rpc_interface.h index 5c9b66d5f55..852cef78301 100644 --- a/modules/multiplayer/scene_rpc_interface.h +++ b/modules/multiplayer/scene_rpc_interface.h @@ -91,6 +91,8 @@ private: #endif protected: + static bool _sort_rpc_names(const Variant &p_l, const Variant &p_r); + void _process_rpc(Node *p_node, const uint16_t p_rpc_method_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset); void _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);