diff options
57 files changed, 974 insertions, 765 deletions
diff --git a/core/SCsub b/core/SCsub index d9167b8f83..14dfa3487f 100644 --- a/core/SCsub +++ b/core/SCsub @@ -183,6 +183,7 @@ SConscript("os/SCsub") SConscript("math/SCsub") SConscript("crypto/SCsub") SConscript("io/SCsub") +SConscript("multiplayer/SCsub") SConscript("debugger/SCsub") SConscript("input/SCsub") SConscript("variant/SCsub") diff --git a/core/core_constants.cpp b/core/core_constants.cpp index 4f3f1fd16e..ef3d9c346b 100644 --- a/core/core_constants.cpp +++ b/core/core_constants.cpp @@ -31,6 +31,7 @@ #include "core_constants.h" #include "core/input/input_event.h" +#include "core/multiplayer/multiplayer.h" #include "core/object/class_db.h" #include "core/os/keyboard.h" #include "core/variant/variant.h" @@ -609,6 +610,15 @@ void register_global_constants() { BIND_CORE_ENUM_CONSTANT(METHOD_FLAG_OBJECT_CORE); BIND_CORE_ENUM_CONSTANT(METHOD_FLAGS_DEFAULT); + // rpc + BIND_CORE_ENUM_CONSTANT_CUSTOM("RPC_MODE_DISABLED", Multiplayer::RPC_MODE_DISABLED); + BIND_CORE_ENUM_CONSTANT_CUSTOM("RPC_MODE_ANY", Multiplayer::RPC_MODE_ANY); + BIND_CORE_ENUM_CONSTANT_CUSTOM("RPC_MODE_AUTH", Multiplayer::RPC_MODE_AUTHORITY); + + BIND_CORE_ENUM_CONSTANT_CUSTOM("TRANSFER_MODE_UNRELIABLE", Multiplayer::TRANSFER_MODE_UNRELIABLE); + BIND_CORE_ENUM_CONSTANT_CUSTOM("TRANSFER_MODE_ORDERED", Multiplayer::TRANSFER_MODE_ORDERED); + BIND_CORE_ENUM_CONSTANT_CUSTOM("TRANSFER_MODE_RELIABLE", Multiplayer::TRANSFER_MODE_RELIABLE); + BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_NIL", Variant::NIL); BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_BOOL", Variant::BOOL); BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_INT", Variant::INT); diff --git a/core/multiplayer/SCsub b/core/multiplayer/SCsub new file mode 100644 index 0000000000..19a6549225 --- /dev/null +++ b/core/multiplayer/SCsub @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +Import("env") + +env.add_source_files(env.core_sources, "*.cpp") diff --git a/core/multiplayer/multiplayer.h b/core/multiplayer/multiplayer.h new file mode 100644 index 0000000000..8ddad61dd0 --- /dev/null +++ b/core/multiplayer/multiplayer.h @@ -0,0 +1,80 @@ +/*************************************************************************/ +/* multiplayer.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef MULTIPLAYER_H +#define MULTIPLAYER_H + +#include "core/variant/binder_common.h" + +#include "core/string/string_name.h" + +namespace Multiplayer { + +enum TransferMode { + TRANSFER_MODE_UNRELIABLE, + TRANSFER_MODE_ORDERED, + TRANSFER_MODE_RELIABLE +}; + +enum RPCMode { + RPC_MODE_DISABLED, // No rpc for this method, calls to this will be blocked (default) + RPC_MODE_ANY, // Any peer can call this rpc() + RPC_MODE_AUTHORITY, // / Only the node's network authority (server by default) can call this rpc() +}; + +struct RPCConfig { + StringName name; + RPCMode rpc_mode = RPC_MODE_DISABLED; + bool sync = false; + TransferMode transfer_mode = TRANSFER_MODE_RELIABLE; + int channel = 0; + + bool operator==(RPCConfig const &p_other) const { + return name == p_other.name; + } +}; + +struct SortRPCConfig { + StringName::AlphCompare compare; + bool operator()(const RPCConfig &p_a, const RPCConfig &p_b) const { + return compare(p_a.name, p_b.name); + } +}; + +}; // namespace Multiplayer + +// This is needed for proper docs generation (i.e. not "Multiplayer."-prefixed). +typedef Multiplayer::RPCMode RPCMode; +typedef Multiplayer::TransferMode TransferMode; + +VARIANT_ENUM_CAST(RPCMode); +VARIANT_ENUM_CAST(TransferMode); + +#endif // MULTIPLAYER_H diff --git a/core/io/multiplayer_api.cpp b/core/multiplayer/multiplayer_api.cpp index c145225751..1130fcf9cb 100644 --- a/core/io/multiplayer_api.cpp +++ b/core/multiplayer/multiplayer_api.cpp @@ -32,7 +32,8 @@ #include "core/debugger/engine_debugger.h" #include "core/io/marshalls.h" -#include "core/io/multiplayer_replicator.h" +#include "core/multiplayer/multiplayer_replicator.h" +#include "core/multiplayer/rpc_manager.h" #include "scene/main/node.h" #include <stdint.h> @@ -41,71 +42,18 @@ #include "core/os/os.h" #endif -String _get_rpc_md5(const Node *p_node) { - String rpc_list; - const Vector<MultiplayerAPI::RPCConfig> node_config = p_node->get_node_rpc_methods(); - for (int i = 0; i < node_config.size(); i++) { - rpc_list += String(node_config[i].name); - } - if (p_node->get_script_instance()) { - const Vector<MultiplayerAPI::RPCConfig> script_config = p_node->get_script_instance()->get_rpc_methods(); - for (int i = 0; i < script_config.size(); i++) { - rpc_list += String(script_config[i].name); - } - } - return rpc_list.md5_text(); -} - -const MultiplayerAPI::RPCConfig _get_rpc_config(const Node *p_node, const StringName &p_method, uint16_t &r_id) { - const Vector<MultiplayerAPI::RPCConfig> node_config = p_node->get_node_rpc_methods(); - for (int i = 0; i < node_config.size(); i++) { - if (node_config[i].name == p_method) { - r_id = ((uint16_t)i) | (1 << 15); - return node_config[i]; - } - } - if (p_node->get_script_instance()) { - const Vector<MultiplayerAPI::RPCConfig> script_config = p_node->get_script_instance()->get_rpc_methods(); - for (int i = 0; i < script_config.size(); i++) { - if (script_config[i].name == p_method) { - r_id = (uint16_t)i; - return script_config[i]; - } - } - } - return MultiplayerAPI::RPCConfig(); -} - -const MultiplayerAPI::RPCConfig _get_rpc_config_by_id(Node *p_node, uint16_t p_id) { - Vector<MultiplayerAPI::RPCConfig> config; - uint16_t id = p_id; - if (id & (1 << 15)) { - id = id & ~(1 << 15); - config = p_node->get_node_rpc_methods(); - } else if (p_node->get_script_instance()) { - config = p_node->get_script_instance()->get_rpc_methods(); - } - if (id < config.size()) { - return config[id]; - } - return MultiplayerAPI::RPCConfig(); -} - -_FORCE_INLINE_ bool _can_call_mode(Node *p_node, MultiplayerAPI::RPCMode mode, int p_remote_id) { - switch (mode) { - case MultiplayerAPI::RPC_MODE_DISABLED: { - return false; - } break; - case MultiplayerAPI::RPC_MODE_ANY: { - return true; - } break; - case MultiplayerAPI::RPC_MODE_AUTHORITY: { - return !p_node->is_network_authority() && p_remote_id == p_node->get_network_authority(); - } break; +#ifdef DEBUG_ENABLED +void MultiplayerAPI::profile_bandwidth(const String &p_inout, int p_size) { + if (EngineDebugger::is_profiling("multiplayer")) { + Array values; + values.push_back("bandwidth"); + values.push_back(p_inout); + values.push_back(OS::get_singleton()->get_ticks_msec()); + values.push_back(p_size); + EngineDebugger::profiler_add_frame_data("multiplayer", values); } - - return false; } +#endif void MultiplayerAPI::poll() { if (!network_peer.is_valid() || network_peer->get_connection_status() == MultiplayerPeer::CONNECTION_DISCONNECTED) { @@ -129,9 +77,9 @@ void MultiplayerAPI::poll() { break; // Something is wrong! } - rpc_sender_id = sender; + remote_sender_id = sender; _process_packet(sender, packet, len); - rpc_sender_id = 0; + remote_sender_id = 0; if (!network_peer.is_valid()) { break; // It's also possible that a packet or RPC caused a disconnection, so also check here. @@ -191,49 +139,16 @@ Ref<MultiplayerPeer> MultiplayerAPI::get_network_peer() const { return network_peer; } -#ifdef DEBUG_ENABLED -void _profile_node_data(const String &p_what, ObjectID p_id) { - if (EngineDebugger::is_profiling("multiplayer")) { - Array values; - values.push_back("node"); - values.push_back(p_id); - values.push_back(p_what); - EngineDebugger::profiler_add_frame_data("multiplayer", values); - } -} - -void _profile_bandwidth_data(const String &p_inout, int p_size) { - if (EngineDebugger::is_profiling("multiplayer")) { - Array values; - values.push_back("bandwidth"); - values.push_back(p_inout); - values.push_back(OS::get_singleton()->get_ticks_msec()); - values.push_back(p_size); - EngineDebugger::profiler_add_frame_data("multiplayer", values); - } -} -#endif - -// Returns the packet size stripping the node path added when the node is not yet cached. -int get_packet_len(uint32_t p_node_target, int p_packet_len) { - if (p_node_target & 0x80000000) { - int ofs = p_node_target & 0x7FFFFFFF; - return p_packet_len - (p_packet_len - ofs); - } else { - return p_packet_len; - } -} - void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_packet_len) { ERR_FAIL_COND_MSG(root_node == nullptr, "Multiplayer root node was not initialized. If you are using custom multiplayer, remember to set the root node via MultiplayerAPI.set_root_node before using it."); ERR_FAIL_COND_MSG(p_packet_len < 1, "Invalid packet received. Size too small."); #ifdef DEBUG_ENABLED - _profile_bandwidth_data("in", p_packet_len); + profile_bandwidth("in", p_packet_len); #endif // Extract the `packet_type` from the LSB three bits: - uint8_t packet_type = p_packet[0] & 7; + uint8_t packet_type = p_packet[0] & CMD_MASK; switch (packet_type) { case NETWORK_COMMAND_SIMPLIFY_PATH: { @@ -245,76 +160,7 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_ } break; case NETWORK_COMMAND_REMOTE_CALL: { - // Extract packet meta - int packet_min_size = 1; - int name_id_offset = 1; - ERR_FAIL_COND_MSG(p_packet_len < packet_min_size, "Invalid packet received. Size too small."); - // Compute the meta size, which depends on the compression level. - int node_id_compression = (p_packet[0] & 24) >> NODE_ID_COMPRESSION_SHIFT; - int name_id_compression = (p_packet[0] & 32) >> NAME_ID_COMPRESSION_SHIFT; - - switch (node_id_compression) { - case NETWORK_NODE_ID_COMPRESSION_8: - packet_min_size += 1; - name_id_offset += 1; - break; - case NETWORK_NODE_ID_COMPRESSION_16: - packet_min_size += 2; - name_id_offset += 2; - break; - case NETWORK_NODE_ID_COMPRESSION_32: - packet_min_size += 4; - name_id_offset += 4; - break; - default: - ERR_FAIL_MSG("Was not possible to extract the node id compression mode."); - } - switch (name_id_compression) { - case NETWORK_NAME_ID_COMPRESSION_8: - packet_min_size += 1; - break; - case NETWORK_NAME_ID_COMPRESSION_16: - packet_min_size += 2; - break; - default: - ERR_FAIL_MSG("Was not possible to extract the name id compression mode."); - } - ERR_FAIL_COND_MSG(p_packet_len < packet_min_size, "Invalid packet received. Size too small."); - - uint32_t node_target = 0; - switch (node_id_compression) { - case NETWORK_NODE_ID_COMPRESSION_8: - node_target = p_packet[1]; - break; - case NETWORK_NODE_ID_COMPRESSION_16: - node_target = decode_uint16(p_packet + 1); - break; - case NETWORK_NODE_ID_COMPRESSION_32: - node_target = decode_uint32(p_packet + 1); - break; - default: - // Unreachable, checked before. - CRASH_NOW(); - } - - Node *node = _process_get_node(p_from, p_packet, node_target, p_packet_len); - ERR_FAIL_COND_MSG(node == nullptr, "Invalid packet received. Requested node was not found."); - - uint16_t name_id = 0; - switch (name_id_compression) { - case NETWORK_NAME_ID_COMPRESSION_8: - name_id = p_packet[name_id_offset]; - break; - case NETWORK_NAME_ID_COMPRESSION_16: - name_id = decode_uint16(p_packet + name_id_offset); - break; - default: - // Unreachable, checked before. - CRASH_NOW(); - } - - const int packet_len = get_packet_len(node_target, p_packet_len); - _process_rpc(node, name_id, p_from, p_packet, packet_len, packet_min_size); + rpc_manager->process_rpc(p_from, p_packet, p_packet_len); } break; case NETWORK_COMMAND_RAW: { @@ -332,101 +178,6 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_ } } -Node *MultiplayerAPI::_process_get_node(int p_from, const uint8_t *p_packet, uint32_t p_node_target, int p_packet_len) { - Node *node = nullptr; - - if (p_node_target & 0x80000000) { - // Use full path (not cached yet). - int ofs = p_node_target & 0x7FFFFFFF; - - ERR_FAIL_COND_V_MSG(ofs >= p_packet_len, nullptr, "Invalid packet received. Size smaller than declared."); - - String paths; - paths.parse_utf8((const char *)&p_packet[ofs], p_packet_len - ofs); - - NodePath np = paths; - - node = root_node->get_node(np); - - if (!node) { - ERR_PRINT("Failed to get path from RPC: " + String(np) + "."); - } - return node; - } else { - // Use cached path. - return get_cached_node(p_from, p_node_target); - } -} - -void MultiplayerAPI::_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) { - ERR_FAIL_COND_MSG(p_offset > p_packet_len, "Invalid packet received. Size too small."); - - // Check that remote can call the RPC on this node. - const RPCConfig config = _get_rpc_config_by_id(p_node, p_rpc_method_id); - ERR_FAIL_COND(config.name == StringName()); - - bool can_call = _can_call_mode(p_node, config.rpc_mode, p_from); - ERR_FAIL_COND_MSG(!can_call, "RPC '" + String(config.name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)config.rpc_mode) + ", authority is " + itos(p_node->get_network_authority()) + "."); - - int argc = 0; - bool byte_only = false; - - const bool byte_only_or_no_args = ((p_packet[0] & 64) >> BYTE_ONLY_OR_NO_ARGS_SHIFT) == 1; - if (byte_only_or_no_args) { - if (p_offset < p_packet_len) { - // This packet contains only bytes. - argc = 1; - byte_only = true; - } else { - // This rpc calls a method without parameters. - } - } else { - // Normal variant, takes the argument count from the packet. - ERR_FAIL_COND_MSG(p_offset >= p_packet_len, "Invalid packet received. Size too small."); - argc = p_packet[p_offset]; - p_offset += 1; - } - - Vector<Variant> args; - Vector<const Variant *> argp; - args.resize(argc); - argp.resize(argc); - -#ifdef DEBUG_ENABLED - _profile_node_data("in_rpc", p_node->get_instance_id()); -#endif - - if (byte_only) { - Vector<uint8_t> pure_data; - const int len = p_packet_len - p_offset; - pure_data.resize(len); - memcpy(pure_data.ptrw(), &p_packet[p_offset], len); - args.write[0] = pure_data; - argp.write[0] = &args[0]; - p_offset += len; - } else { - for (int i = 0; i < argc; i++) { - ERR_FAIL_COND_MSG(p_offset >= p_packet_len, "Invalid packet received. Size too small."); - - int vlen; - Error err = decode_and_decompress_variant(args.write[i], &p_packet[p_offset], p_packet_len - p_offset, &vlen); - ERR_FAIL_COND_MSG(err != OK, "Invalid packet received. Unable to decode RPC argument."); - - argp.write[i] = &args[i]; - p_offset += vlen; - } - } - - Callable::CallError ce; - - p_node->call(config.name, (const Variant **)argp.ptr(), argc, ce); - if (ce.error != Callable::CallError::CALL_OK) { - String error = Variant::get_call_error_text(p_node, config.name, (const Variant **)argp.ptr(), argc, ce); - error = "RPC - " + error; - ERR_PRINT(error); - } -} - void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet, int p_packet_len) { ERR_FAIL_COND_MSG(p_packet_len < 38, "Invalid packet received. Size too small."); int ofs = 1; @@ -449,7 +200,7 @@ void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet, Node *node = root_node->get_node(path); ERR_FAIL_COND(node == nullptr); - const bool valid_rpc_checksum = _get_rpc_md5(node) == methods_md5; + const bool valid_rpc_checksum = rpc_manager->get_rpc_md5(node) == methods_md5; 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); } @@ -471,7 +222,7 @@ void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet, encode_cstring(pname.get_data(), &packet.write[2]); network_peer->set_transfer_channel(0); - network_peer->set_transfer_mode(MultiplayerPeer::TRANSFER_MODE_RELIABLE); + network_peer->set_transfer_mode(Multiplayer::TRANSFER_MODE_RELIABLE); network_peer->set_target_peer(p_from); network_peer->put_packet(packet.ptr(), packet.size()); } @@ -532,7 +283,7 @@ bool MultiplayerAPI::_send_confirm_path(Node *p_node, NodePath p_path, PathSentC const int path_len = encode_cstring(path.get_data(), nullptr); // Extract MD5 from rpc methods list. - const String methods_md5 = _get_rpc_md5(p_node); + const String methods_md5 = rpc_manager->get_rpc_md5(p_node); const int methods_md5_len = 33; // 32 + 1 for the `0` that is added by the encoder. Vector<uint8_t> packet; @@ -551,7 +302,7 @@ bool MultiplayerAPI::_send_confirm_path(Node *p_node, NodePath p_path, PathSentC for (int &E : peers_to_add) { network_peer->set_target_peer(E); // To all of you. network_peer->set_transfer_channel(0); - network_peer->set_transfer_mode(MultiplayerPeer::TRANSFER_MODE_RELIABLE); + network_peer->set_transfer_mode(Multiplayer::TRANSFER_MODE_RELIABLE); network_peer->put_packet(packet.ptr(), packet.size()); psc->confirmed_peers.insert(E, false); // Insert into confirmed, but as false since it was not confirmed. @@ -716,188 +467,6 @@ Error MultiplayerAPI::decode_and_decompress_variant(Variant &r_variant, const ui return OK; } -void MultiplayerAPI::_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) { - ERR_FAIL_COND_MSG(network_peer.is_null(), "Attempt to remote call/set when networking is not active in SceneTree."); - - ERR_FAIL_COND_MSG(network_peer->get_connection_status() == MultiplayerPeer::CONNECTION_CONNECTING, "Attempt to remote call/set when networking is not connected yet in SceneTree."); - - ERR_FAIL_COND_MSG(network_peer->get_connection_status() == MultiplayerPeer::CONNECTION_DISCONNECTED, "Attempt to remote call/set when networking is disconnected."); - - ERR_FAIL_COND_MSG(p_argcount > 255, "Too many arguments >255."); - - if (p_to != 0 && !connected_peers.has(ABS(p_to))) { - ERR_FAIL_COND_MSG(p_to == network_peer->get_unique_id(), "Attempt to remote call/set yourself! unique ID: " + itos(network_peer->get_unique_id()) + "."); - - ERR_FAIL_MSG("Attempt to remote call unexisting ID: " + itos(p_to) + "."); - } - - NodePath from_path = (root_node->get_path()).rel_path_to(p_from->get_path()); - ERR_FAIL_COND_MSG(from_path.is_empty(), "Unable to send RPC. Relative path is empty. THIS IS LIKELY A BUG IN THE ENGINE!"); - - // See if the path is cached. - PathSentCache *psc = path_send_cache.getptr(from_path); - if (!psc) { - // Path is not cached, create. - path_send_cache[from_path] = PathSentCache(); - psc = path_send_cache.getptr(from_path); - psc->id = last_send_cache_id++; - } - - // See if all peers have cached path (if so, call can be fast). - const bool has_all_peers = _send_confirm_path(p_from, from_path, psc, p_to); - - // Create base packet, lots of hardcode because it must be tight. - - int ofs = 0; - -#define MAKE_ROOM(m_amount) \ - if (packet_cache.size() < m_amount) \ - packet_cache.resize(m_amount); - - // Encode meta. - // The meta is composed by a single byte that contains (starting from the least significant bit): - // - `NetworkCommands` in the first three bits. - // - `NetworkNodeIdCompression` in the next 2 bits. - // - `NetworkNameIdCompression` in the next 1 bit. - // - `byte_only_or_no_args` in the next 1 bit. - // - So we still have the last bit free! - uint8_t command_type = NETWORK_COMMAND_REMOTE_CALL; - uint8_t node_id_compression = UINT8_MAX; - uint8_t name_id_compression = UINT8_MAX; - bool byte_only_or_no_args = false; - - MAKE_ROOM(1); - // The meta is composed along the way, so just set 0 for now. - packet_cache.write[0] = 0; - ofs += 1; - - // Encode Node ID. - if (has_all_peers) { - // Compress the node ID only if all the target peers already know it. - if (psc->id >= 0 && psc->id <= 255) { - // We can encode the id in 1 byte - node_id_compression = NETWORK_NODE_ID_COMPRESSION_8; - MAKE_ROOM(ofs + 1); - packet_cache.write[ofs] = static_cast<uint8_t>(psc->id); - ofs += 1; - } else if (psc->id >= 0 && psc->id <= 65535) { - // We can encode the id in 2 bytes - node_id_compression = NETWORK_NODE_ID_COMPRESSION_16; - MAKE_ROOM(ofs + 2); - encode_uint16(static_cast<uint16_t>(psc->id), &(packet_cache.write[ofs])); - ofs += 2; - } else { - // Too big, let's use 4 bytes. - node_id_compression = NETWORK_NODE_ID_COMPRESSION_32; - MAKE_ROOM(ofs + 4); - encode_uint32(psc->id, &(packet_cache.write[ofs])); - ofs += 4; - } - } else { - // The targets don't know the node yet, so we need to use 32 bits int. - node_id_compression = NETWORK_NODE_ID_COMPRESSION_32; - MAKE_ROOM(ofs + 4); - encode_uint32(psc->id, &(packet_cache.write[ofs])); - ofs += 4; - } - - // Encode method ID - if (p_rpc_id <= UINT8_MAX) { - // The ID fits in 1 byte - name_id_compression = NETWORK_NAME_ID_COMPRESSION_8; - MAKE_ROOM(ofs + 1); - packet_cache.write[ofs] = static_cast<uint8_t>(p_rpc_id); - ofs += 1; - } else { - // The ID is larger, let's use 2 bytes - name_id_compression = NETWORK_NAME_ID_COMPRESSION_16; - MAKE_ROOM(ofs + 2); - encode_uint16(p_rpc_id, &(packet_cache.write[ofs])); - ofs += 2; - } - - if (p_argcount == 0) { - byte_only_or_no_args = true; - } else if (p_argcount == 1 && p_arg[0]->get_type() == Variant::PACKED_BYTE_ARRAY) { - byte_only_or_no_args = true; - // Special optimization when only the byte vector is sent. - const Vector<uint8_t> data = *p_arg[0]; - MAKE_ROOM(ofs + data.size()); - memcpy(&(packet_cache.write[ofs]), data.ptr(), sizeof(uint8_t) * data.size()); - ofs += data.size(); - } else { - // Arguments - MAKE_ROOM(ofs + 1); - packet_cache.write[ofs] = p_argcount; - ofs += 1; - for (int i = 0; i < p_argcount; i++) { - int len(0); - Error err = encode_and_compress_variant(*p_arg[i], nullptr, len); - ERR_FAIL_COND_MSG(err != OK, "Unable to encode RPC argument. THIS IS LIKELY A BUG IN THE ENGINE!"); - MAKE_ROOM(ofs + len); - encode_and_compress_variant(*p_arg[i], &(packet_cache.write[ofs]), len); - ofs += len; - } - } - - ERR_FAIL_COND(command_type > 7); - ERR_FAIL_COND(node_id_compression > 3); - ERR_FAIL_COND(name_id_compression > 1); - - // We can now set the meta - packet_cache.write[0] = command_type + (node_id_compression << NODE_ID_COMPRESSION_SHIFT) + (name_id_compression << NAME_ID_COMPRESSION_SHIFT) + ((byte_only_or_no_args ? 1 : 0) << BYTE_ONLY_OR_NO_ARGS_SHIFT); - -#ifdef DEBUG_ENABLED - _profile_bandwidth_data("out", ofs); -#endif - - // Take chance and set transfer mode, since all send methods will use it. - network_peer->set_transfer_channel(p_config.channel); - network_peer->set_transfer_mode(p_config.transfer_mode); - - if (has_all_peers) { - // They all have verified paths, so send fast. - network_peer->set_target_peer(p_to); // To all of you. - network_peer->put_packet(packet_cache.ptr(), ofs); // A message with love. - } 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); - - // Not all verified path, so send one by one. - - // Append path at the end, since we will need it for some packets. - 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 (Set<int>::Element *E = connected_peers.front(); E; E = E->next()) { - if (p_to < 0 && E->get() == -p_to) { - continue; // Continue, excluded. - } - - if (p_to > 0 && E->get() != p_to) { - continue; // Continue, not for this peer. - } - - Map<int, bool>::Element *F = psc->confirmed_peers.find(E->get()); - ERR_CONTINUE(!F); // Should never happen. - - network_peer->set_target_peer(E->get()); // To this one specifically. - - if (F->get()) { - // This one confirmed path, so use id. - encode_uint32(psc->id, &(packet_cache.write[1])); - network_peer->put_packet(packet_cache.ptr(), ofs); - } else { - // This one did not confirm path yet, so use entire path (sorry!). - encode_uint32(0x80000000 | ofs, &(packet_cache.write[1])); // Offset to path and flag. - network_peer->put_packet(packet_cache.ptr(), ofs + path_len); - } - } - } -} - void MultiplayerAPI::_add_peer(int p_id) { connected_peers.insert(p_id); path_get_cache.insert(p_id, PathGetCache()); @@ -934,72 +503,15 @@ void MultiplayerAPI::_server_disconnected() { emit_signal(SNAME("server_disconnected")); } -void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount) { - ERR_FAIL_COND_MSG(!network_peer.is_valid(), "Trying to call an RPC while no network peer is active."); - ERR_FAIL_COND_MSG(!p_node->is_inside_tree(), "Trying to call an RPC on a node which is not inside SceneTree."); - ERR_FAIL_COND_MSG(network_peer->get_connection_status() != MultiplayerPeer::CONNECTION_CONNECTED, "Trying to call an RPC via a network peer which is not connected."); - - int node_id = network_peer->get_unique_id(); - bool call_local_native = false; - bool call_local_script = false; - uint16_t rpc_id = UINT16_MAX; - const RPCConfig config = _get_rpc_config(p_node, p_method, rpc_id); - ERR_FAIL_COND_MSG(config.name == StringName(), - vformat("Unable to get the RPC configuration for the function \"%s\" at path: \"%s\". This happens when the method is not marked for RPCs.", p_method, p_node->get_path())); - if (p_peer_id == 0 || p_peer_id == node_id || (p_peer_id < 0 && p_peer_id != -node_id)) { - if (rpc_id & (1 << 15)) { - call_local_native = config.sync; - } else { - call_local_script = config.sync; - } - } - - if (p_peer_id != node_id) { -#ifdef DEBUG_ENABLED - _profile_node_data("out_rpc", p_node->get_instance_id()); -#endif - - _send_rpc(p_node, p_peer_id, rpc_id, config, p_method, p_arg, p_argcount); - } - - if (call_local_native) { - int temp_id = rpc_sender_id; - rpc_sender_id = get_network_unique_id(); - Callable::CallError ce; - p_node->call(p_method, p_arg, p_argcount, ce); - rpc_sender_id = temp_id; - if (ce.error != Callable::CallError::CALL_OK) { - String error = Variant::get_call_error_text(p_node, p_method, p_arg, p_argcount, ce); - error = "rpc() aborted in local call: - " + error + "."; - ERR_PRINT(error); - return; - } - } - - if (call_local_script) { - int temp_id = rpc_sender_id; - rpc_sender_id = get_network_unique_id(); - Callable::CallError ce; - ce.error = Callable::CallError::CALL_OK; - p_node->get_script_instance()->call(p_method, p_arg, p_argcount, ce); - rpc_sender_id = temp_id; - if (ce.error != Callable::CallError::CALL_OK) { - String error = Variant::get_call_error_text(p_node, p_method, p_arg, p_argcount, ce); - error = "rpc() aborted in script local call: - " + error + "."; - ERR_PRINT(error); - return; - } - } - - ERR_FAIL_COND_MSG(p_peer_id == node_id && !config.sync, "RPC '" + p_method + "' on yourself is not allowed by selected mode."); -} - -Error MultiplayerAPI::send_bytes(Vector<uint8_t> p_data, int p_to, MultiplayerPeer::TransferMode p_mode, int p_channel) { +Error MultiplayerAPI::send_bytes(Vector<uint8_t> p_data, int p_to, Multiplayer::TransferMode p_mode, int p_channel) { ERR_FAIL_COND_V_MSG(p_data.size() < 1, ERR_INVALID_DATA, "Trying to send an empty raw packet."); ERR_FAIL_COND_V_MSG(!network_peer.is_valid(), ERR_UNCONFIGURED, "Trying to send a raw packet while no network peer is active."); ERR_FAIL_COND_V_MSG(network_peer->get_connection_status() != MultiplayerPeer::CONNECTION_CONNECTED, ERR_UNCONFIGURED, "Trying to send a raw packet via a network peer which is not connected."); - MAKE_ROOM(p_data.size() + 1); + if (packet_cache.size() < p_data.size() + 1) { + packet_cache.resize(p_data.size() + 1); + } + const uint8_t *r = p_data.ptr(); packet_cache.write[0] = NETWORK_COMMAND_RAW; memcpy(&packet_cache.write[1], &r[0], p_data.size()); @@ -1024,6 +536,14 @@ void MultiplayerAPI::_process_raw(int p_from, const uint8_t *p_packet, int p_pac emit_signal(SNAME("network_peer_packet"), p_from, out); } +bool MultiplayerAPI::is_cache_confirmed(NodePath p_path, int p_peer) { + const PathSentCache *psc = path_send_cache.getptr(p_path); + ERR_FAIL_COND_V(!psc, false); + const Map<int, bool>::Element *F = psc->confirmed_peers.find(p_peer); + ERR_FAIL_COND_V(!F, false); // Should never happen. + return F->get(); +} + bool MultiplayerAPI::send_confirm_path(Node *p_node, NodePath p_path, int p_peer_id, int &r_id) { // See if the path is cached. PathSentCache *psc = path_send_cache.getptr(p_path); @@ -1092,23 +612,23 @@ bool MultiplayerAPI::is_object_decoding_allowed() const { return allow_object_decoding; } -MultiplayerReplicator *MultiplayerAPI::get_replicator() const { - return replicator; -} - void MultiplayerAPI::scene_enter_exit_notify(const String &p_scene, Node *p_node, bool p_enter) { replicator->scene_enter_exit_notify(p_scene, p_node, p_enter); } +void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount) { + rpc_manager->rpcp(p_node, p_peer_id, p_method, p_arg, p_argcount); +} + void MultiplayerAPI::_bind_methods() { ClassDB::bind_method(D_METHOD("set_root_node", "node"), &MultiplayerAPI::set_root_node); ClassDB::bind_method(D_METHOD("get_root_node"), &MultiplayerAPI::get_root_node); - ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id", "mode", "channel"), &MultiplayerAPI::send_bytes, DEFVAL(MultiplayerPeer::TARGET_PEER_BROADCAST), DEFVAL(MultiplayerPeer::TRANSFER_MODE_RELIABLE), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id", "mode", "channel"), &MultiplayerAPI::send_bytes, DEFVAL(MultiplayerPeer::TARGET_PEER_BROADCAST), DEFVAL(Multiplayer::TRANSFER_MODE_RELIABLE), DEFVAL(0)); ClassDB::bind_method(D_METHOD("has_network_peer"), &MultiplayerAPI::has_network_peer); ClassDB::bind_method(D_METHOD("get_network_peer"), &MultiplayerAPI::get_network_peer); ClassDB::bind_method(D_METHOD("get_network_unique_id"), &MultiplayerAPI::get_network_unique_id); ClassDB::bind_method(D_METHOD("is_network_server"), &MultiplayerAPI::is_network_server); - ClassDB::bind_method(D_METHOD("get_rpc_sender_id"), &MultiplayerAPI::get_rpc_sender_id); + ClassDB::bind_method(D_METHOD("get_remote_sender_id"), &MultiplayerAPI::get_remote_sender_id); ClassDB::bind_method(D_METHOD("set_network_peer", "peer"), &MultiplayerAPI::set_network_peer); ClassDB::bind_method(D_METHOD("poll"), &MultiplayerAPI::poll); ClassDB::bind_method(D_METHOD("clear"), &MultiplayerAPI::clear); @@ -1133,18 +653,16 @@ void MultiplayerAPI::_bind_methods() { ADD_SIGNAL(MethodInfo("connected_to_server")); ADD_SIGNAL(MethodInfo("connection_failed")); ADD_SIGNAL(MethodInfo("server_disconnected")); - - BIND_ENUM_CONSTANT(RPC_MODE_DISABLED); - BIND_ENUM_CONSTANT(RPC_MODE_ANY); - BIND_ENUM_CONSTANT(RPC_MODE_AUTHORITY); } MultiplayerAPI::MultiplayerAPI() { replicator = memnew(MultiplayerReplicator(this)); + rpc_manager = memnew(RPCManager(this)); clear(); } MultiplayerAPI::~MultiplayerAPI() { clear(); memdelete(replicator); + memdelete(rpc_manager); } diff --git a/core/io/multiplayer_api.h b/core/multiplayer/multiplayer_api.h index 3c96a3eed1..acabda62e2 100644 --- a/core/io/multiplayer_api.h +++ b/core/multiplayer/multiplayer_api.h @@ -31,41 +31,17 @@ #ifndef MULTIPLAYER_API_H #define MULTIPLAYER_API_H -#include "core/io/multiplayer_peer.h" -#include "core/io/resource_uid.h" +#include "core/multiplayer/multiplayer.h" +#include "core/multiplayer/multiplayer_peer.h" #include "core/object/ref_counted.h" class MultiplayerReplicator; +class RPCManager; class MultiplayerAPI : public RefCounted { GDCLASS(MultiplayerAPI, RefCounted); public: - enum RPCMode { - RPC_MODE_DISABLED, // No rpc for this method, calls to this will be blocked (default) - RPC_MODE_ANY, // Any peer can call this rpc() - RPC_MODE_AUTHORITY, // Only the node's network authority (server by default) can call this rpc() - }; - - struct RPCConfig { - StringName name; - RPCMode rpc_mode = RPC_MODE_DISABLED; - bool sync = false; - MultiplayerPeer::TransferMode transfer_mode = MultiplayerPeer::TRANSFER_MODE_RELIABLE; - int channel = 0; - - bool operator==(RPCConfig const &p_other) const { - return name == p_other.name; - } - }; - - struct SortRPCConfig { - StringName::AlphCompare compare; - bool operator()(const RPCConfig &p_a, const RPCConfig &p_b) const { - return compare(p_a.name, p_b.name); - } - }; - enum NetworkCommands { NETWORK_COMMAND_REMOTE_CALL = 0, NETWORK_COMMAND_SIMPLIFY_PATH, @@ -73,24 +49,20 @@ public: NETWORK_COMMAND_RAW, NETWORK_COMMAND_SPAWN, NETWORK_COMMAND_DESPAWN, - NETWORK_COMMAND_SYNC, // This is the max we can have. We should optmize simplify/confirm, possibly spawn/despawn. + NETWORK_COMMAND_SYNC, }; - enum NetworkNodeIdCompression { - NETWORK_NODE_ID_COMPRESSION_8 = 0, - NETWORK_NODE_ID_COMPRESSION_16, - NETWORK_NODE_ID_COMPRESSION_32, - }; - - enum NetworkNameIdCompression { - NETWORK_NAME_ID_COMPRESSION_8 = 0, - NETWORK_NAME_ID_COMPRESSION_16, + // For each command, the 4 MSB can contain custom flags, as defined by subsystems. + enum { + CMD_FLAG_0_SHIFT = 4, + CMD_FLAG_1_SHIFT = 5, + CMD_FLAG_2_SHIFT = 6, + CMD_FLAG_3_SHIFT = 7, }; + // This is the mask that will be used to extract the command. enum { - NODE_ID_COMPRESSION_SHIFT = 3, - NAME_ID_COMPRESSION_SHIFT = 5, - BYTE_ONLY_OR_NO_ARGS_SHIFT = 6, + CMD_MASK = 7, // 0x7 -> 0b00001111 }; private: @@ -111,29 +83,30 @@ private: }; Ref<MultiplayerPeer> network_peer; - int rpc_sender_id = 0; Set<int> connected_peers; + int remote_sender_id = 0; + int remote_sender_override = 0; + HashMap<NodePath, PathSentCache> path_send_cache; Map<int, PathGetCache> path_get_cache; int last_send_cache_id; Vector<uint8_t> packet_cache; + Node *root_node = nullptr; bool allow_object_decoding = false; + MultiplayerReplicator *replicator = nullptr; + RPCManager *rpc_manager = nullptr; protected: static void _bind_methods(); + bool _send_confirm_path(Node *p_node, NodePath p_path, PathSentCache *psc, int p_target); void _process_packet(int p_from, const uint8_t *p_packet, int p_packet_len); void _process_simplify_path(int p_from, const uint8_t *p_packet, int p_packet_len); void _process_confirm_path(int p_from, const uint8_t *p_packet, int p_packet_len); - Node *_process_get_node(int p_from, const uint8_t *p_packet, uint32_t p_node_target, int p_packet_len); - 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 _process_raw(int p_from, const uint8_t *p_packet, int p_packet_len); - 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); - bool _send_confirm_path(Node *p_node, NodePath p_path, PathSentCache *psc, int p_target); - public: void poll(); void clear(); @@ -141,18 +114,20 @@ public: Node *get_root_node(); void set_network_peer(const Ref<MultiplayerPeer> &p_peer); Ref<MultiplayerPeer> get_network_peer() const; - Error send_bytes(Vector<uint8_t> p_data, int p_to = MultiplayerPeer::TARGET_PEER_BROADCAST, MultiplayerPeer::TransferMode p_mode = MultiplayerPeer::TRANSFER_MODE_RELIABLE, int p_channel = 0); + + Error send_bytes(Vector<uint8_t> p_data, int p_to = MultiplayerPeer::TARGET_PEER_BROADCAST, Multiplayer::TransferMode p_mode = Multiplayer::TRANSFER_MODE_RELIABLE, int p_channel = 0); Error encode_and_compress_variant(const Variant &p_variant, uint8_t *p_buffer, int &r_len); Error decode_and_decompress_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len); // Called by Node.rpc - void rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount); + void rpcp(Node *p_node, int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount); // Called by Node._notification void scene_enter_exit_notify(const String &p_scene, Node *p_node, bool p_enter); // Called by replicator bool send_confirm_path(Node *p_node, NodePath p_path, int p_target, int &p_id); Node *get_cached_node(int p_from, uint32_t p_node_id); + bool is_cache_confirmed(NodePath p_path, int p_peer); void _add_peer(int p_id); void _del_peer(int p_id); @@ -162,7 +137,9 @@ public: bool has_network_peer() const { return network_peer.is_valid(); } Vector<int> get_network_connected_peers() const; - int get_rpc_sender_id() const { return rpc_sender_id; } + const Set<int> get_connected_peers() const { return connected_peers; } + int get_remote_sender_id() const { return remote_sender_override ? remote_sender_override : remote_sender_id; } + void set_remote_sender_override(int p_id) { remote_sender_override = p_id; } int get_network_unique_id() const; bool is_network_server() const; void set_refuse_new_network_connections(bool p_refuse); @@ -171,12 +148,15 @@ public: void set_allow_object_decoding(bool p_enable); bool is_object_decoding_allowed() const; - MultiplayerReplicator *get_replicator() const; + MultiplayerReplicator *get_replicator() const { return replicator; } + RPCManager *get_rpc_manager() const { return rpc_manager; } + +#ifdef DEBUG_ENABLED + void profile_bandwidth(const String &p_inout, int p_size); +#endif MultiplayerAPI(); ~MultiplayerAPI(); }; -VARIANT_ENUM_CAST(MultiplayerAPI::RPCMode); - #endif // MULTIPLAYER_API_H diff --git a/core/io/multiplayer_peer.cpp b/core/multiplayer/multiplayer_peer.cpp index 83cf24d7e3..40847102d8 100644 --- a/core/io/multiplayer_peer.cpp +++ b/core/multiplayer/multiplayer_peer.cpp @@ -75,10 +75,6 @@ void MultiplayerPeer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "transfer_mode", PROPERTY_HINT_ENUM, "Unreliable,Unreliable Ordered,Reliable"), "set_transfer_mode", "get_transfer_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "transfer_channel", PROPERTY_HINT_RANGE, "0,255,1"), "set_transfer_channel", "get_transfer_channel"); - BIND_ENUM_CONSTANT(TRANSFER_MODE_UNRELIABLE); - BIND_ENUM_CONSTANT(TRANSFER_MODE_UNRELIABLE_ORDERED); - BIND_ENUM_CONSTANT(TRANSFER_MODE_RELIABLE); - BIND_ENUM_CONSTANT(CONNECTION_DISCONNECTED); BIND_ENUM_CONSTANT(CONNECTION_CONNECTING); BIND_ENUM_CONSTANT(CONNECTION_CONNECTED); diff --git a/core/io/multiplayer_peer.h b/core/multiplayer/multiplayer_peer.h index 7ca4e7930b..ba00c3b41b 100644 --- a/core/io/multiplayer_peer.h +++ b/core/multiplayer/multiplayer_peer.h @@ -32,6 +32,7 @@ #define NETWORKED_MULTIPLAYER_PEER_H #include "core/io/packet_peer.h" +#include "core/multiplayer/multiplayer.h" class MultiplayerPeer : public PacketPeer { GDCLASS(MultiplayerPeer, PacketPeer); @@ -44,11 +45,6 @@ public: TARGET_PEER_BROADCAST = 0, TARGET_PEER_SERVER = 1 }; - enum TransferMode { - TRANSFER_MODE_UNRELIABLE, - TRANSFER_MODE_UNRELIABLE_ORDERED, - TRANSFER_MODE_RELIABLE, - }; enum ConnectionStatus { CONNECTION_DISCONNECTED, @@ -58,8 +54,8 @@ public: virtual void set_transfer_channel(int p_channel) = 0; virtual int get_transfer_channel() const = 0; - virtual void set_transfer_mode(TransferMode p_mode) = 0; - virtual TransferMode get_transfer_mode() const = 0; + virtual void set_transfer_mode(Multiplayer::TransferMode p_mode) = 0; + virtual Multiplayer::TransferMode get_transfer_mode() const = 0; virtual void set_target_peer(int p_peer_id) = 0; virtual int get_packet_peer() const = 0; @@ -79,7 +75,6 @@ public: MultiplayerPeer() {} }; -VARIANT_ENUM_CAST(MultiplayerPeer::TransferMode) VARIANT_ENUM_CAST(MultiplayerPeer::ConnectionStatus) #endif // NETWORKED_MULTIPLAYER_PEER_H diff --git a/core/io/multiplayer_replicator.cpp b/core/multiplayer/multiplayer_replicator.cpp index b9d0675af1..0340e11288 100644 --- a/core/io/multiplayer_replicator.cpp +++ b/core/multiplayer/multiplayer_replicator.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "core/io/multiplayer_replicator.h" +#include "core/multiplayer/multiplayer_replicator.h" #include "core/io/marshalls.h" #include "scene/main/node.h" @@ -88,7 +88,7 @@ Error MultiplayerReplicator::_sync_all_default(const ResourceUID::ID &p_scene_id } int ofs = 0; uint8_t *ptr = packet_cache.ptrw(); - ptr[0] = MultiplayerAPI::NETWORK_COMMAND_SYNC + ((same_size ? 1 : 0) << MultiplayerAPI::BYTE_ONLY_OR_NO_ARGS_SHIFT); + ptr[0] = MultiplayerAPI::NETWORK_COMMAND_SYNC | (same_size ? BYTE_OR_ZERO_FLAG : 0); ofs = 1; ofs += encode_uint64(p_scene_id, &ptr[ofs]); ptr[ofs] = cfg.sync_recv++; @@ -116,7 +116,7 @@ Error MultiplayerReplicator::_sync_all_default(const ResourceUID::ID &p_scene_id Ref<MultiplayerPeer> network_peer = multiplayer->get_network_peer(); network_peer->set_target_peer(p_peer); network_peer->set_transfer_channel(0); - network_peer->set_transfer_mode(MultiplayerPeer::TRANSFER_MODE_UNRELIABLE); + network_peer->set_transfer_mode(Multiplayer::TRANSFER_MODE_UNRELIABLE); return network_peer->put_packet(ptr, ofs); } @@ -125,7 +125,7 @@ void MultiplayerReplicator::_process_default_sync(const ResourceUID::ID &p_id, c ERR_FAIL_COND_MSG(!replications.has(p_id), "Invalid spawn ID received " + itos(p_id)); SceneConfig &cfg = replications[p_id]; ERR_FAIL_COND_MSG(cfg.mode != REPLICATION_MODE_SERVER || multiplayer->is_network_server(), "The defualt implementation only allows sync packets from the server"); - const bool same_size = ((p_packet[0] & 64) >> MultiplayerAPI::BYTE_ONLY_OR_NO_ARGS_SHIFT) == 1; + const bool same_size = p_packet[0] & BYTE_OR_ZERO_FLAG; int ofs = SYNC_CMD_OFFSET; int time = p_packet[ofs]; // Skip old update. @@ -218,7 +218,7 @@ Error MultiplayerReplicator::_send_default_spawn_despawn(int p_peer_id, const Re int nlen = encode_cstring(cname.get_data(), nullptr); MAKE_ROOM(SPAWN_CMD_OFFSET + 4 + 4 + nlen + state_len); uint8_t *ptr = packet_cache.ptrw(); - ptr[0] = (p_spawn ? MultiplayerAPI::NETWORK_COMMAND_SPAWN : MultiplayerAPI::NETWORK_COMMAND_DESPAWN) + ((is_raw ? 1 : 0) << MultiplayerAPI::BYTE_ONLY_OR_NO_ARGS_SHIFT); + ptr[0] = (p_spawn ? MultiplayerAPI::NETWORK_COMMAND_SPAWN : MultiplayerAPI::NETWORK_COMMAND_DESPAWN) | (is_raw ? BYTE_OR_ZERO_FLAG : 0); ofs = 1; ofs += encode_uint64(p_scene_id, &ptr[ofs]); ofs += encode_uint32(path_id, &ptr[ofs]); @@ -236,7 +236,7 @@ Error MultiplayerReplicator::_send_default_spawn_despawn(int p_peer_id, const Re Ref<MultiplayerPeer> network_peer = multiplayer->get_network_peer(); network_peer->set_target_peer(p_peer_id); network_peer->set_transfer_channel(0); - network_peer->set_transfer_mode(MultiplayerPeer::TRANSFER_MODE_RELIABLE); + network_peer->set_transfer_mode(Multiplayer::TRANSFER_MODE_RELIABLE); return network_peer->put_packet(ptr, ofs + state_len); } @@ -262,7 +262,7 @@ void MultiplayerReplicator::_process_default_spawn_despawn(int p_from, const Res if (cfg.mode == REPLICATION_MODE_SERVER && p_from == 1) { String scene_path = ResourceUID::get_singleton()->get_id_path(p_scene_id); if (p_spawn) { - const bool is_raw = ((p_packet[0] & 64) >> MultiplayerAPI::BYTE_ONLY_OR_NO_ARGS_SHIFT) == 1; + const bool is_raw = ((p_packet[0] & BYTE_OR_ZERO_FLAG) >> BYTE_OR_ZERO_SHIFT) == 1; ERR_FAIL_COND_MSG(parent->has_node(name), vformat("Unable to spawn node. Node already exists: %s/%s", parent->get_path(), name)); RES res = ResourceLoader::load(scene_path); @@ -308,7 +308,7 @@ void MultiplayerReplicator::process_spawn_despawn(int p_from, const uint8_t *p_p const SceneConfig &cfg = replications[id]; if (cfg.on_spawn_despawn_receive.is_valid()) { int ofs = SPAWN_CMD_OFFSET; - bool is_raw = ((p_packet[0] & 64) >> MultiplayerAPI::BYTE_ONLY_OR_NO_ARGS_SHIFT) == 1; + bool is_raw = ((p_packet[0] & BYTE_OR_ZERO_FLAG) >> BYTE_OR_ZERO_SHIFT) == 1; Variant data; int left = p_packet_len - ofs; if (is_raw && left) { @@ -466,7 +466,7 @@ Error MultiplayerReplicator::spawn_config(const ResourceUID::ID &p_id, Replicati SceneConfig cfg; cfg.mode = p_mode; for (int i = 0; i < p_props.size(); i++) { - cfg.properties.push_back(StringName(p_props[i])); + cfg.properties.push_back(p_props[i]); } cfg.on_spawn_despawn_send = p_on_send; cfg.on_spawn_despawn_receive = p_on_recv; @@ -505,7 +505,7 @@ Error MultiplayerReplicator::_send_spawn_despawn(int p_peer_id, const ResourceUI } MAKE_ROOM(SPAWN_CMD_OFFSET + data_size); uint8_t *ptr = packet_cache.ptrw(); - ptr[0] = (p_spawn ? MultiplayerAPI::NETWORK_COMMAND_SPAWN : MultiplayerAPI::NETWORK_COMMAND_DESPAWN) + ((is_raw ? 1 : 0) << MultiplayerAPI::BYTE_ONLY_OR_NO_ARGS_SHIFT); + ptr[0] = (p_spawn ? MultiplayerAPI::NETWORK_COMMAND_SPAWN : MultiplayerAPI::NETWORK_COMMAND_DESPAWN) + ((is_raw ? 1 : 0) << BYTE_OR_ZERO_SHIFT); encode_uint64(p_scene_id, &ptr[1]); if (p_data.get_type() == Variant::PACKED_BYTE_ARRAY) { const PackedByteArray pba = p_data; @@ -516,7 +516,7 @@ Error MultiplayerReplicator::_send_spawn_despawn(int p_peer_id, const ResourceUI Ref<MultiplayerPeer> network_peer = multiplayer->get_network_peer(); network_peer->set_target_peer(p_peer_id); network_peer->set_transfer_channel(0); - network_peer->set_transfer_mode(MultiplayerPeer::TRANSFER_MODE_RELIABLE); + network_peer->set_transfer_mode(Multiplayer::TRANSFER_MODE_RELIABLE); return network_peer->put_packet(ptr, SPAWN_CMD_OFFSET + data_size); } @@ -740,7 +740,7 @@ Error MultiplayerReplicator::sync_all(const ResourceUID::ID &p_scene_id, int p_p return OK; } -Error MultiplayerReplicator::send_sync(int p_peer_id, const ResourceUID::ID &p_scene_id, PackedByteArray p_data, MultiplayerPeer::TransferMode p_transfer_mode, int p_channel) { +Error MultiplayerReplicator::send_sync(int p_peer_id, const ResourceUID::ID &p_scene_id, PackedByteArray p_data, Multiplayer::TransferMode p_transfer_mode, int p_channel) { ERR_FAIL_COND_V(!multiplayer->has_network_peer(), ERR_UNCONFIGURED); ERR_FAIL_COND_V(!replications.has(p_scene_id), ERR_INVALID_PARAMETER); const SceneConfig &cfg = replications[p_scene_id]; @@ -768,7 +768,7 @@ void MultiplayerReplicator::_bind_methods() { ClassDB::bind_method(D_METHOD("spawn", "scene_id", "object", "peer_id"), &MultiplayerReplicator::spawn, DEFVAL(0)); ClassDB::bind_method(D_METHOD("send_despawn", "peer_id", "scene_id", "data", "path"), &MultiplayerReplicator::send_despawn, DEFVAL(Variant()), DEFVAL(NodePath())); ClassDB::bind_method(D_METHOD("send_spawn", "peer_id", "scene_id", "data", "path"), &MultiplayerReplicator::send_spawn, DEFVAL(Variant()), DEFVAL(NodePath())); - ClassDB::bind_method(D_METHOD("send_sync", "peer_id", "scene_id", "data", "transfer_mode", "channel"), &MultiplayerReplicator::send_sync, DEFVAL(MultiplayerPeer::TRANSFER_MODE_RELIABLE), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("send_sync", "peer_id", "scene_id", "data", "transfer_mode", "channel"), &MultiplayerReplicator::send_sync, DEFVAL(Multiplayer::TRANSFER_MODE_RELIABLE), DEFVAL(0)); ClassDB::bind_method(D_METHOD("sync_all", "scene_id", "peer_id"), &MultiplayerReplicator::sync_all, DEFVAL(0)); ClassDB::bind_method(D_METHOD("track", "scene_id", "object"), &MultiplayerReplicator::track); ClassDB::bind_method(D_METHOD("untrack", "scene_id", "object"), &MultiplayerReplicator::untrack); diff --git a/core/io/multiplayer_replicator.h b/core/multiplayer/multiplayer_replicator.h index 2630ad7a8a..7fa774fdf4 100644 --- a/core/io/multiplayer_replicator.h +++ b/core/multiplayer/multiplayer_replicator.h @@ -31,8 +31,9 @@ #ifndef MULTIPLAYER_REPLICATOR_H #define MULTIPLAYER_REPLICATOR_H -#include "core/io/multiplayer_api.h" +#include "core/multiplayer/multiplayer_api.h" +#include "core/io/resource_uid.h" #include "core/templates/hash_map.h" #include "core/variant/typed_array.h" @@ -68,6 +69,14 @@ protected: static void _bind_methods(); private: + enum { + BYTE_OR_ZERO_SHIFT = MultiplayerAPI::CMD_FLAG_0_SHIFT, + }; + + enum { + BYTE_OR_ZERO_FLAG = 1 << BYTE_OR_ZERO_SHIFT, + }; + MultiplayerAPI *multiplayer = nullptr; Vector<uint8_t> packet_cache; Map<ResourceUID::ID, SceneConfig> replications; @@ -108,7 +117,7 @@ public: // Sync Error sync_config(const ResourceUID::ID &p_id, uint64_t p_interval, const TypedArray<StringName> &p_props = TypedArray<StringName>(), const Callable &p_on_send = Callable(), const Callable &p_on_recv = Callable()); Error sync_all(const ResourceUID::ID &p_scene_id, int p_peer); - Error send_sync(int p_peer_id, const ResourceUID::ID &p_scene_id, PackedByteArray p_data, MultiplayerPeer::TransferMode p_mode, int p_channel); + Error send_sync(int p_peer_id, const ResourceUID::ID &p_scene_id, PackedByteArray p_data, Multiplayer::TransferMode p_mode, int p_channel); void track(const ResourceUID::ID &p_scene_id, Object *p_object); void untrack(const ResourceUID::ID &p_scene_id, Object *p_object); diff --git a/core/multiplayer/rpc_manager.cpp b/core/multiplayer/rpc_manager.cpp new file mode 100644 index 0000000000..135dc4a187 --- /dev/null +++ b/core/multiplayer/rpc_manager.cpp @@ -0,0 +1,525 @@ +/*************************************************************************/ +/* rpc_manager.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "core/multiplayer/rpc_manager.h" + +#include "core/debugger/engine_debugger.h" +#include "core/io/marshalls.h" +#include "core/multiplayer/multiplayer_api.h" +#include "scene/main/node.h" + +#ifdef DEBUG_ENABLED +_FORCE_INLINE_ void RPCManager::_profile_node_data(const String &p_what, ObjectID p_id) { + if (EngineDebugger::is_profiling("multiplayer")) { + Array values; + values.push_back("node"); + values.push_back(p_id); + values.push_back(p_what); + EngineDebugger::profiler_add_frame_data("multiplayer", values); + } +} +#else +_FORCE_INLINE_ void RPCManager::_profile_node_data(const String &p_what, ObjectID p_id) {} +#endif + +// Returns the packet size stripping the node path added when the node is not yet cached. +int get_packet_len(uint32_t p_node_target, int p_packet_len) { + if (p_node_target & 0x80000000) { + int ofs = p_node_target & 0x7FFFFFFF; + return p_packet_len - (p_packet_len - ofs); + } else { + return p_packet_len; + } +} + +const Multiplayer::RPCConfig _get_rpc_config(const Node *p_node, const StringName &p_method, uint16_t &r_id) { + const Vector<Multiplayer::RPCConfig> node_config = p_node->get_node_rpc_methods(); + for (int i = 0; i < node_config.size(); i++) { + if (node_config[i].name == p_method) { + r_id = ((uint16_t)i) | (1 << 15); + return node_config[i]; + } + } + if (p_node->get_script_instance()) { + const Vector<Multiplayer::RPCConfig> script_config = p_node->get_script_instance()->get_rpc_methods(); + for (int i = 0; i < script_config.size(); i++) { + if (script_config[i].name == p_method) { + r_id = (uint16_t)i; + return script_config[i]; + } + } + } + return Multiplayer::RPCConfig(); +} + +const Multiplayer::RPCConfig _get_rpc_config_by_id(Node *p_node, uint16_t p_id) { + Vector<Multiplayer::RPCConfig> config; + uint16_t id = p_id; + if (id & (1 << 15)) { + id = id & ~(1 << 15); + config = p_node->get_node_rpc_methods(); + } else if (p_node->get_script_instance()) { + config = p_node->get_script_instance()->get_rpc_methods(); + } + if (id < config.size()) { + return config[id]; + } + return Multiplayer::RPCConfig(); +} + +_FORCE_INLINE_ bool _can_call_mode(Node *p_node, Multiplayer::RPCMode mode, int p_remote_id) { + switch (mode) { + case Multiplayer::RPC_MODE_DISABLED: { + return false; + } break; + case Multiplayer::RPC_MODE_ANY: { + return true; + } break; + case Multiplayer::RPC_MODE_AUTHORITY: { + return !p_node->is_network_authority() && p_remote_id == p_node->get_network_authority(); + } break; + } + + return false; +} + +String RPCManager::get_rpc_md5(const Node *p_node) { + String rpc_list; + const Vector<Multiplayer::RPCConfig> node_config = p_node->get_node_rpc_methods(); + for (int i = 0; i < node_config.size(); i++) { + rpc_list += String(node_config[i].name); + } + if (p_node->get_script_instance()) { + const Vector<Multiplayer::RPCConfig> script_config = p_node->get_script_instance()->get_rpc_methods(); + for (int i = 0; i < script_config.size(); i++) { + rpc_list += String(script_config[i].name); + } + } + return rpc_list.md5_text(); +} + +Node *RPCManager::_process_get_node(int p_from, const uint8_t *p_packet, uint32_t p_node_target, int p_packet_len) { + Node *node = nullptr; + + if (p_node_target & 0x80000000) { + // Use full path (not cached yet). + int ofs = p_node_target & 0x7FFFFFFF; + + ERR_FAIL_COND_V_MSG(ofs >= p_packet_len, nullptr, "Invalid packet received. Size smaller than declared."); + + String paths; + paths.parse_utf8((const char *)&p_packet[ofs], p_packet_len - ofs); + + NodePath np = paths; + + node = multiplayer->get_root_node()->get_node(np); + + if (!node) { + ERR_PRINT("Failed to get path from RPC: " + String(np) + "."); + } + return node; + } else { + // Use cached path. + return multiplayer->get_cached_node(p_from, p_node_target); + } +} + +void RPCManager::process_rpc(int p_from, const uint8_t *p_packet, int p_packet_len) { + // Extract packet meta + int packet_min_size = 1; + int name_id_offset = 1; + ERR_FAIL_COND_MSG(p_packet_len < packet_min_size, "Invalid packet received. Size too small."); + // Compute the meta size, which depends on the compression level. + int node_id_compression = (p_packet[0] & NODE_ID_COMPRESSION_FLAG) >> NODE_ID_COMPRESSION_SHIFT; + int name_id_compression = (p_packet[0] & NAME_ID_COMPRESSION_FLAG) >> NAME_ID_COMPRESSION_SHIFT; + + switch (node_id_compression) { + case NETWORK_NODE_ID_COMPRESSION_8: + packet_min_size += 1; + name_id_offset += 1; + break; + case NETWORK_NODE_ID_COMPRESSION_16: + packet_min_size += 2; + name_id_offset += 2; + break; + case NETWORK_NODE_ID_COMPRESSION_32: + packet_min_size += 4; + name_id_offset += 4; + break; + default: + ERR_FAIL_MSG("Was not possible to extract the node id compression mode."); + } + switch (name_id_compression) { + case NETWORK_NAME_ID_COMPRESSION_8: + packet_min_size += 1; + break; + case NETWORK_NAME_ID_COMPRESSION_16: + packet_min_size += 2; + break; + default: + ERR_FAIL_MSG("Was not possible to extract the name id compression mode."); + } + ERR_FAIL_COND_MSG(p_packet_len < packet_min_size, "Invalid packet received. Size too small."); + + uint32_t node_target = 0; + switch (node_id_compression) { + case NETWORK_NODE_ID_COMPRESSION_8: + node_target = p_packet[1]; + break; + case NETWORK_NODE_ID_COMPRESSION_16: + node_target = decode_uint16(p_packet + 1); + break; + case NETWORK_NODE_ID_COMPRESSION_32: + node_target = decode_uint32(p_packet + 1); + break; + default: + // Unreachable, checked before. + CRASH_NOW(); + } + + Node *node = _process_get_node(p_from, p_packet, node_target, p_packet_len); + ERR_FAIL_COND_MSG(node == nullptr, "Invalid packet received. Requested node was not found."); + + uint16_t name_id = 0; + switch (name_id_compression) { + case NETWORK_NAME_ID_COMPRESSION_8: + name_id = p_packet[name_id_offset]; + break; + case NETWORK_NAME_ID_COMPRESSION_16: + name_id = decode_uint16(p_packet + name_id_offset); + break; + default: + // Unreachable, checked before. + CRASH_NOW(); + } + + const int packet_len = get_packet_len(node_target, p_packet_len); + _process_rpc(node, name_id, p_from, p_packet, packet_len, packet_min_size); +} + +void RPCManager::_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) { + ERR_FAIL_COND_MSG(p_offset > p_packet_len, "Invalid packet received. Size too small."); + + // Check that remote can call the RPC on this node. + const Multiplayer::RPCConfig config = _get_rpc_config_by_id(p_node, p_rpc_method_id); + ERR_FAIL_COND(config.name == StringName()); + + bool can_call = _can_call_mode(p_node, config.rpc_mode, p_from); + ERR_FAIL_COND_MSG(!can_call, "RPC '" + String(config.name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)config.rpc_mode) + ", authority is " + itos(p_node->get_network_authority()) + "."); + + int argc = 0; + bool byte_only = false; + + const bool byte_only_or_no_args = p_packet[0] & BYTE_ONLY_OR_NO_ARGS_FLAG; + if (byte_only_or_no_args) { + if (p_offset < p_packet_len) { + // This packet contains only bytes. + argc = 1; + byte_only = true; + } else { + // This rpc calls a method without parameters. + } + } else { + // Normal variant, takes the argument count from the packet. + ERR_FAIL_COND_MSG(p_offset >= p_packet_len, "Invalid packet received. Size too small."); + argc = p_packet[p_offset]; + p_offset += 1; + } + + Vector<Variant> args; + Vector<const Variant *> argp; + args.resize(argc); + argp.resize(argc); + +#ifdef DEBUG_ENABLED + _profile_node_data("in_rpc", p_node->get_instance_id()); +#endif + + if (byte_only) { + Vector<uint8_t> pure_data; + const int len = p_packet_len - p_offset; + pure_data.resize(len); + memcpy(pure_data.ptrw(), &p_packet[p_offset], len); + args.write[0] = pure_data; + argp.write[0] = &args[0]; + p_offset += len; + } else { + for (int i = 0; i < argc; i++) { + ERR_FAIL_COND_MSG(p_offset >= p_packet_len, "Invalid packet received. Size too small."); + + int vlen; + Error err = multiplayer->decode_and_decompress_variant(args.write[i], &p_packet[p_offset], p_packet_len - p_offset, &vlen); + ERR_FAIL_COND_MSG(err != OK, "Invalid packet received. Unable to decode RPC argument."); + + argp.write[i] = &args[i]; + p_offset += vlen; + } + } + + Callable::CallError ce; + + p_node->call(config.name, (const Variant **)argp.ptr(), argc, ce); + if (ce.error != Callable::CallError::CALL_OK) { + String error = Variant::get_call_error_text(p_node, config.name, (const Variant **)argp.ptr(), argc, ce); + error = "RPC - " + error; + ERR_PRINT(error); + } +} + +void RPCManager::_send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, const Multiplayer::RPCConfig &p_config, const StringName &p_name, const Variant **p_arg, int p_argcount) { + Ref<MultiplayerPeer> network_peer = multiplayer->get_network_peer(); + ERR_FAIL_COND_MSG(network_peer.is_null(), "Attempt to remote call/set when networking is not active in SceneTree."); + + ERR_FAIL_COND_MSG(network_peer->get_connection_status() == MultiplayerPeer::CONNECTION_CONNECTING, "Attempt to remote call/set when networking is not connected yet in SceneTree."); + + ERR_FAIL_COND_MSG(network_peer->get_connection_status() == MultiplayerPeer::CONNECTION_DISCONNECTED, "Attempt to remote call/set when networking is disconnected."); + + ERR_FAIL_COND_MSG(p_argcount > 255, "Too many arguments >255."); + + if (p_to != 0 && !multiplayer->get_network_connected_peers().has(ABS(p_to))) { + ERR_FAIL_COND_MSG(p_to == network_peer->get_unique_id(), "Attempt to remote call/set yourself! unique ID: " + itos(network_peer->get_unique_id()) + "."); + + ERR_FAIL_MSG("Attempt to remote call unexisting ID: " + itos(p_to) + "."); + } + + NodePath from_path = (multiplayer->get_root_node()->get_path()).rel_path_to(p_from->get_path()); + ERR_FAIL_COND_MSG(from_path.is_empty(), "Unable to send RPC. Relative path is empty. THIS IS LIKELY A BUG IN THE ENGINE!"); + + // See if all peers have cached path (if so, call can be fast). + int psc_id; + const bool has_all_peers = multiplayer->send_confirm_path(p_from, from_path, p_to, psc_id); + + // Create base packet, lots of hardcode because it must be tight. + + int ofs = 0; + +#define MAKE_ROOM(m_amount) \ + if (packet_cache.size() < m_amount) \ + packet_cache.resize(m_amount); + + // Encode meta. + uint8_t command_type = MultiplayerAPI::NETWORK_COMMAND_REMOTE_CALL; + uint8_t node_id_compression = UINT8_MAX; + uint8_t name_id_compression = UINT8_MAX; + bool byte_only_or_no_args = false; + + MAKE_ROOM(1); + // The meta is composed along the way, so just set 0 for now. + packet_cache.write[0] = 0; + ofs += 1; + + // Encode Node ID. + if (has_all_peers) { + // Compress the node ID only if all the target peers already know it. + if (psc_id >= 0 && psc_id <= 255) { + // We can encode the id in 1 byte + node_id_compression = NETWORK_NODE_ID_COMPRESSION_8; + MAKE_ROOM(ofs + 1); + packet_cache.write[ofs] = static_cast<uint8_t>(psc_id); + ofs += 1; + } else if (psc_id >= 0 && psc_id <= 65535) { + // We can encode the id in 2 bytes + node_id_compression = NETWORK_NODE_ID_COMPRESSION_16; + MAKE_ROOM(ofs + 2); + encode_uint16(static_cast<uint16_t>(psc_id), &(packet_cache.write[ofs])); + ofs += 2; + } else { + // Too big, let's use 4 bytes. + node_id_compression = NETWORK_NODE_ID_COMPRESSION_32; + MAKE_ROOM(ofs + 4); + encode_uint32(psc_id, &(packet_cache.write[ofs])); + ofs += 4; + } + } else { + // The targets don't know the node yet, so we need to use 32 bits int. + node_id_compression = NETWORK_NODE_ID_COMPRESSION_32; + MAKE_ROOM(ofs + 4); + encode_uint32(psc_id, &(packet_cache.write[ofs])); + ofs += 4; + } + + // Encode method ID + if (p_rpc_id <= UINT8_MAX) { + // The ID fits in 1 byte + name_id_compression = NETWORK_NAME_ID_COMPRESSION_8; + MAKE_ROOM(ofs + 1); + packet_cache.write[ofs] = static_cast<uint8_t>(p_rpc_id); + ofs += 1; + } else { + // The ID is larger, let's use 2 bytes + name_id_compression = NETWORK_NAME_ID_COMPRESSION_16; + MAKE_ROOM(ofs + 2); + encode_uint16(p_rpc_id, &(packet_cache.write[ofs])); + ofs += 2; + } + + if (p_argcount == 0) { + byte_only_or_no_args = true; + } else if (p_argcount == 1 && p_arg[0]->get_type() == Variant::PACKED_BYTE_ARRAY) { + byte_only_or_no_args = true; + // Special optimization when only the byte vector is sent. + const Vector<uint8_t> data = *p_arg[0]; + MAKE_ROOM(ofs + data.size()); + memcpy(&(packet_cache.write[ofs]), data.ptr(), sizeof(uint8_t) * data.size()); + ofs += data.size(); + } else { + // Arguments + MAKE_ROOM(ofs + 1); + packet_cache.write[ofs] = p_argcount; + ofs += 1; + for (int i = 0; i < p_argcount; i++) { + int len(0); + Error err = multiplayer->encode_and_compress_variant(*p_arg[i], nullptr, len); + ERR_FAIL_COND_MSG(err != OK, "Unable to encode RPC argument. THIS IS LIKELY A BUG IN THE ENGINE!"); + MAKE_ROOM(ofs + len); + multiplayer->encode_and_compress_variant(*p_arg[i], &(packet_cache.write[ofs]), len); + ofs += len; + } + } + + ERR_FAIL_COND(command_type > 7); + ERR_FAIL_COND(node_id_compression > 3); + ERR_FAIL_COND(name_id_compression > 1); + + // We can now set the meta + packet_cache.write[0] = command_type + (node_id_compression << NODE_ID_COMPRESSION_SHIFT) + (name_id_compression << NAME_ID_COMPRESSION_SHIFT) + (byte_only_or_no_args ? BYTE_ONLY_OR_NO_ARGS_FLAG : 0); + +#ifdef DEBUG_ENABLED + multiplayer->profile_bandwidth("out", ofs); +#endif + + // Take chance and set transfer mode, since all send methods will use it. + network_peer->set_transfer_channel(p_config.channel); + network_peer->set_transfer_mode(p_config.transfer_mode); + + if (has_all_peers) { + // They all have verified paths, so send fast. + network_peer->set_target_peer(p_to); // To all of you. + network_peer->put_packet(packet_cache.ptr(), ofs); // A message with love. + } 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); + + // Not all verified path, so send one by one. + + // Append path at the end, since we will need it for some packets. + 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. + } + + bool confirmed = multiplayer->is_cache_confirmed(from_path, P); + + network_peer->set_target_peer(P); // To this one specifically. + + if (confirmed) { + // This one confirmed path, so use id. + encode_uint32(psc_id, &(packet_cache.write[1])); + network_peer->put_packet(packet_cache.ptr(), ofs); + } else { + // This one did not confirm path yet, so use entire path (sorry!). + encode_uint32(0x80000000 | ofs, &(packet_cache.write[1])); // Offset to path and flag. + network_peer->put_packet(packet_cache.ptr(), ofs + path_len); + } + } + } +} + +void RPCManager::rpcp(Node *p_node, int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount) { + Ref<MultiplayerPeer> network_peer = multiplayer->get_network_peer(); + ERR_FAIL_COND_MSG(!network_peer.is_valid(), "Trying to call an RPC while no network peer is active."); + ERR_FAIL_COND_MSG(!p_node->is_inside_tree(), "Trying to call an RPC on a node which is not inside SceneTree."); + ERR_FAIL_COND_MSG(network_peer->get_connection_status() != MultiplayerPeer::CONNECTION_CONNECTED, "Trying to call an RPC via a network peer which is not connected."); + + int node_id = network_peer->get_unique_id(); + bool call_local_native = false; + bool call_local_script = false; + uint16_t rpc_id = UINT16_MAX; + const Multiplayer::RPCConfig config = _get_rpc_config(p_node, p_method, rpc_id); + ERR_FAIL_COND_MSG(config.name == StringName(), + vformat("Unable to get the RPC configuration for the function \"%s\" at path: \"%s\". This happens when the method is not marked for RPCs.", p_method, p_node->get_path())); + if (p_peer_id == 0 || p_peer_id == node_id || (p_peer_id < 0 && p_peer_id != -node_id)) { + if (rpc_id & (1 << 15)) { + call_local_native = config.sync; + } else { + call_local_script = config.sync; + } + } + + if (p_peer_id != node_id) { +#ifdef DEBUG_ENABLED + _profile_node_data("out_rpc", p_node->get_instance_id()); +#endif + + _send_rpc(p_node, p_peer_id, rpc_id, config, p_method, p_arg, p_argcount); + } + + if (call_local_native) { + Callable::CallError ce; + + multiplayer->set_remote_sender_override(network_peer->get_unique_id()); + p_node->call(p_method, p_arg, p_argcount, ce); + multiplayer->set_remote_sender_override(0); + + if (ce.error != Callable::CallError::CALL_OK) { + String error = Variant::get_call_error_text(p_node, p_method, p_arg, p_argcount, ce); + error = "rpc() aborted in local call: - " + error + "."; + ERR_PRINT(error); + return; + } + } + + if (call_local_script) { + Callable::CallError ce; + ce.error = Callable::CallError::CALL_OK; + + multiplayer->set_remote_sender_override(network_peer->get_unique_id()); + p_node->get_script_instance()->call(p_method, p_arg, p_argcount, ce); + multiplayer->set_remote_sender_override(0); + + if (ce.error != Callable::CallError::CALL_OK) { + String error = Variant::get_call_error_text(p_node, p_method, p_arg, p_argcount, ce); + error = "rpc() aborted in script local call: - " + error + "."; + ERR_PRINT(error); + return; + } + } + + ERR_FAIL_COND_MSG(p_peer_id == node_id && !config.sync, "RPC '" + p_method + "' on yourself is not allowed by selected mode."); +} diff --git a/core/multiplayer/rpc_manager.h b/core/multiplayer/rpc_manager.h new file mode 100644 index 0000000000..7b99dee226 --- /dev/null +++ b/core/multiplayer/rpc_manager.h @@ -0,0 +1,89 @@ +/*************************************************************************/ +/* rpc_manager.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef MULTIPLAYER_RPC_H +#define MULTIPLAYER_RPC_H + +#include "core/multiplayer/multiplayer.h" +#include "core/multiplayer/multiplayer_api.h" +#include "core/object/ref_counted.h" + +class RPCManager : public RefCounted { + GDCLASS(RPCManager, RefCounted); + +private: + enum NetworkNodeIdCompression { + NETWORK_NODE_ID_COMPRESSION_8 = 0, + NETWORK_NODE_ID_COMPRESSION_16, + NETWORK_NODE_ID_COMPRESSION_32, + }; + + enum NetworkNameIdCompression { + NETWORK_NAME_ID_COMPRESSION_8 = 0, + NETWORK_NAME_ID_COMPRESSION_16, + }; + + // The RPC meta is composed by a single byte that contains (starting from the least significant bit): + // - `NetworkCommands` in the first four bits. + // - `NetworkNodeIdCompression` in the next 2 bits. + // - `NetworkNameIdCompression` in the next 1 bit. + // - `byte_only_or_no_args` in the next 1 bit. + enum { + NODE_ID_COMPRESSION_SHIFT = MultiplayerAPI::CMD_FLAG_0_SHIFT, // 2 bits for this. + NAME_ID_COMPRESSION_SHIFT = MultiplayerAPI::CMD_FLAG_2_SHIFT, + BYTE_ONLY_OR_NO_ARGS_SHIFT = MultiplayerAPI::CMD_FLAG_3_SHIFT, + }; + + enum { + NODE_ID_COMPRESSION_FLAG = (1 << NODE_ID_COMPRESSION_SHIFT) | (1 << (NODE_ID_COMPRESSION_SHIFT + 1)), // 2 bits for this. + NAME_ID_COMPRESSION_FLAG = (1 << NAME_ID_COMPRESSION_SHIFT), + BYTE_ONLY_OR_NO_ARGS_FLAG = (1 << BYTE_ONLY_OR_NO_ARGS_SHIFT), + }; + + MultiplayerAPI *multiplayer = nullptr; + Vector<uint8_t> packet_cache; + +protected: + _FORCE_INLINE_ void _profile_node_data(const String &p_what, ObjectID p_id); + 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 Multiplayer::RPCConfig &p_config, const StringName &p_name, const Variant **p_arg, int p_argcount); + Node *_process_get_node(int p_from, const uint8_t *p_packet, uint32_t p_node_target, int p_packet_len); + +public: + // Called by Node.rpc + void rpcp(Node *p_node, int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount); + void process_rpc(int p_from, const uint8_t *p_packet, int p_packet_len); + + String get_rpc_md5(const Node *p_node); + RPCManager(MultiplayerAPI *p_multiplayer) { multiplayer = p_multiplayer; } +}; + +#endif // MULTIPLAYER_RPC_H diff --git a/core/object/script_language.h b/core/object/script_language.h index 385bf79c1a..8d76cbf479 100644 --- a/core/object/script_language.h +++ b/core/object/script_language.h @@ -32,8 +32,8 @@ #define SCRIPT_LANGUAGE_H #include "core/doc_data.h" -#include "core/io/multiplayer_api.h" #include "core/io/resource.h" +#include "core/multiplayer/multiplayer.h" #include "core/templates/map.h" #include "core/templates/pair.h" @@ -159,7 +159,7 @@ public: virtual bool is_placeholder_fallback_enabled() const { return false; } - virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const = 0; + virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const = 0; Script() {} }; @@ -200,7 +200,7 @@ public: virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid); virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid); - virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const = 0; + virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const = 0; virtual ScriptLanguage *get_language() = 0; virtual ~ScriptInstance(); @@ -419,7 +419,7 @@ public: virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid = nullptr); virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid = nullptr); - virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const { return Vector<MultiplayerAPI::RPCConfig>(); } + virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const { return Vector<Multiplayer::RPCConfig>(); } PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref<Script> p_script, Object *p_owner); ~PlaceHolderScriptInstance(); diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index 6c7d9cbd89..3a037f9dd1 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -48,9 +48,6 @@ #include "core/io/image_loader.h" #include "core/io/json.h" #include "core/io/marshalls.h" -#include "core/io/multiplayer_api.h" -#include "core/io/multiplayer_peer.h" -#include "core/io/multiplayer_replicator.h" #include "core/io/packed_data_container.h" #include "core/io/packet_peer.h" #include "core/io/packet_peer_dtls.h" @@ -70,6 +67,9 @@ #include "core/math/geometry_3d.h" #include "core/math/random_number_generator.h" #include "core/math/triangle_mesh.h" +#include "core/multiplayer/multiplayer_api.h" +#include "core/multiplayer/multiplayer_peer.h" +#include "core/multiplayer/multiplayer_replicator.h" #include "core/object/class_db.h" #include "core/object/undo_redo.h" #include "core/os/main_loop.h" diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index 616d88c7f3..4f9aaa9a61 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -2463,6 +2463,24 @@ <constant name="METHOD_FLAGS_DEFAULT" value="1" enum="MethodFlags"> Default method flags. </constant> + <constant name="RPC_MODE_DISABLED" value="0" enum="RPCMode"> + Used with [method Node.rpc_config] to disable a method or property for all RPC calls, making it unavailable. Default for all methods. + </constant> + <constant name="RPC_MODE_ANY" value="1" enum="RPCMode"> + Used with [method Node.rpc_config] to set a method to be callable remotely by any peer. Analogous to the [code]@rpc(any)[/code] annotation. Calls are accepted from all remote peers, no matter if they are node's authority or not. + </constant> + <constant name="RPC_MODE_AUTH" value="2" enum="RPCMode"> + Used with [method Node.rpc_config] to set a method to be callable remotely only by the current network authority (which is the server by default). Analogous to the [code]@rpc(auth)[/code] annotation. See [method Node.set_network_authority]. + </constant> + <constant name="TRANSFER_MODE_UNRELIABLE" value="0" enum="TransferMode"> + Packets are not acknowledged, no resend attempts are made for lost packets. Packets may arrive in any order. Potentially faster than [constant TRANSFER_MODE_ORDERED]. Use for non-critical data, and always consider whether the order matters. + </constant> + <constant name="TRANSFER_MODE_ORDERED" value="1" enum="TransferMode"> + Packets are not acknowledged, no resend attempts are made for lost packets. Packets are received in the order they were sent in. Potentially faster than [constant TRANSFER_MODE_RELIABLE]. Use for non-critical data or data that would be outdated if received late due to resend attempt(s) anyway, for example movement and positional data. + </constant> + <constant name="TRANSFER_MODE_RELIABLE" value="2" enum="TransferMode"> + Packets must be received and resend attempts should be made until the packets are acknowledged. Packets must be received in the order they were sent in. Most reliable transfer mode, but potentially the slowest due to the overhead. Use for critical data that must be transmitted and arrive in order, for example an ability being triggered or a chat message. Consider carefully if the information really is critical, and use sparingly. + </constant> <constant name="TYPE_NIL" value="0" enum="Variant.Type"> Variable is [code]null[/code]. </constant> diff --git a/doc/classes/MultiplayerAPI.xml b/doc/classes/MultiplayerAPI.xml index 70046fc3e9..9c688f7b8b 100644 --- a/doc/classes/MultiplayerAPI.xml +++ b/doc/classes/MultiplayerAPI.xml @@ -30,7 +30,7 @@ Returns the unique peer ID of this MultiplayerAPI's [member network_peer]. </description> </method> - <method name="get_rpc_sender_id" qualifiers="const"> + <method name="get_remote_sender_id" qualifiers="const"> <return type="int" /> <description> Returns the sender's peer ID for the RPC currently being executed. @@ -60,7 +60,7 @@ <return type="int" enum="Error" /> <argument index="0" name="bytes" type="PackedByteArray" /> <argument index="1" name="id" type="int" default="0" /> - <argument index="2" name="mode" type="int" enum="MultiplayerPeer.TransferMode" default="2" /> + <argument index="2" name="mode" type="int" enum="TransferMode" default="2" /> <argument index="3" name="channel" type="int" default="0" /> <description> Sends the given raw [code]bytes[/code] to a specific peer identified by [code]id[/code] (see [method MultiplayerPeer.set_target_peer]). Default ID is [code]0[/code], i.e. broadcast to all peers. @@ -122,14 +122,5 @@ </signal> </signals> <constants> - <constant name="RPC_MODE_DISABLED" value="0" enum="RPCMode"> - Used with [method Node.rpc_config] to disable a method or property for all RPC calls, making it unavailable. Default for all methods. - </constant> - <constant name="RPC_MODE_ANY" value="1" enum="RPCMode"> - Used with [method Node.rpc_config] to set a method to be callable remotely by any peer. Analogous to the [code]@rpc(any)[/code] annotation. Calls are accepted from all remote peers, no matter if they are node's authority or not. - </constant> - <constant name="RPC_MODE_AUTHORITY" value="2" enum="RPCMode"> - Used with [method Node.rpc_config] to set a method to be callable remotely only by the current network authority (which is the server by default). Analogous to the [code]@rpc(auth)[/code] annotation. See [method Node.set_network_authority]. - </constant> </constants> </class> diff --git a/doc/classes/MultiplayerPeer.xml b/doc/classes/MultiplayerPeer.xml index adaa359168..6ee6fce49f 100644 --- a/doc/classes/MultiplayerPeer.xml +++ b/doc/classes/MultiplayerPeer.xml @@ -57,9 +57,9 @@ </member> <member name="transfer_channel" type="int" setter="set_transfer_channel" getter="get_transfer_channel" default="0"> The channel to use to send packets. Many network APIs such as ENet and WebRTC allow the creation of multiple independent channels which behaves, in a way, like separate connections. This means that reliable data will only block delivery of other packets on that channel, and ordering will only be in respect to the channel the packet is being sent on. Using different channels to send [b]different and independent[/b] state updates is a common way to optimize network usage and decrease latency in fast-paced games. - [b]Note:[/b] The default channel ([code]0[/code]) actually works as 3 separate channels (one for each [enum TransferMode]) so that [constant TRANSFER_MODE_RELIABLE] and [constant TRANSFER_MODE_UNRELIABLE_ORDERED] does not interact with each other by default. Refer to the specific network API documentation (e.g. ENet or WebRTC) to learn how to set up channels correctly. + [b]Note:[/b] The default channel ([code]0[/code]) actually works as 3 separate channels (one for each [enum TransferMode]) so that [constant TRANSFER_MODE_RELIABLE] and [constant TRANSFER_MODE_ORDERED] does not interact with each other by default. Refer to the specific network API documentation (e.g. ENet or WebRTC) to learn how to set up channels correctly. </member> - <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" enum="MultiplayerPeer.TransferMode" default="0"> + <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" enum="TransferMode" default="0"> The manner in which to send packets to the [code]target_peer[/code]. See [enum TransferMode]. </member> </members> @@ -93,15 +93,6 @@ </signal> </signals> <constants> - <constant name="TRANSFER_MODE_UNRELIABLE" value="0" enum="TransferMode"> - Packets are not acknowledged, no resend attempts are made for lost packets. Packets may arrive in any order. Potentially faster than [constant TRANSFER_MODE_UNRELIABLE_ORDERED]. Use for non-critical data, and always consider whether the order matters. - </constant> - <constant name="TRANSFER_MODE_UNRELIABLE_ORDERED" value="1" enum="TransferMode"> - Packets are not acknowledged, no resend attempts are made for lost packets. Packets are received in the order they were sent in. Potentially faster than [constant TRANSFER_MODE_RELIABLE]. Use for non-critical data or data that would be outdated if received late due to resend attempt(s) anyway, for example movement and positional data. - </constant> - <constant name="TRANSFER_MODE_RELIABLE" value="2" enum="TransferMode"> - Packets must be received and resend attempts should be made until the packets are acknowledged. Packets must be received in the order they were sent in. Most reliable transfer mode, but potentially the slowest due to the overhead. Use for critical data that must be transmitted and arrive in order, for example an ability being triggered or a chat message. Consider carefully if the information really is critical, and use sparingly. - </constant> <constant name="CONNECTION_DISCONNECTED" value="0" enum="ConnectionStatus"> The ongoing connection disconnected. </constant> diff --git a/doc/classes/MultiplayerReplicator.xml b/doc/classes/MultiplayerReplicator.xml index 0778a7335f..2657f835c4 100644 --- a/doc/classes/MultiplayerReplicator.xml +++ b/doc/classes/MultiplayerReplicator.xml @@ -62,7 +62,7 @@ <argument index="0" name="peer_id" type="int" /> <argument index="1" name="scene_id" type="int" /> <argument index="2" name="data" type="PackedByteArray" /> - <argument index="3" name="transfer_mode" type="int" enum="MultiplayerPeer.TransferMode" default="2" /> + <argument index="3" name="transfer_mode" type="int" enum="TransferMode" default="2" /> <argument index="4" name="channel" type="int" default="0" /> <description> Sends a sync request for the instances of the scene identified by [code]scene_id[/code] to the given [code]peer_id[/code] (see [method MultiplayerPeer.set_target_peer]). This function can only be called manually when overriding the send and receive sync functions (see [method sync_config]). diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index 7d79c50466..1f5823c37c 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -584,11 +584,11 @@ <method name="rpc_config"> <return type="int" /> <argument index="0" name="method" type="StringName" /> - <argument index="1" name="rpc_mode" type="int" enum="MultiplayerAPI.RPCMode" /> - <argument index="2" name="transfer_mode" type="int" enum="MultiplayerPeer.TransferMode" default="2" /> + <argument index="1" name="rpc_mode" type="int" enum="RPCMode" /> + <argument index="2" name="transfer_mode" type="int" enum="TransferMode" default="2" /> <argument index="3" name="channel" type="int" default="0" /> <description> - Changes the RPC mode for the given [code]method[/code] to the given [code]rpc_mode[/code], optionally specifying the [code]transfer_mode[/code] and [code]channel[/code] (on supported peers). See [enum MultiplayerAPI.RPCMode] and [enum MultiplayerPeer.TransferMode]. An alternative is annotating methods and properties with the corresponding annotation ([code]@rpc(any)[/code], [code]@rpc(auth)[/code]). By default, methods are not exposed to networking (and RPCs). + Changes the RPC mode for the given [code]method[/code] to the given [code]rpc_mode[/code], optionally specifying the [code]transfer_mode[/code] and [code]channel[/code] (on supported peers). See [enum RPCMode] and [enum TransferMode]. An alternative is annotating methods and properties with the corresponding annotation ([code]@rpc(any)[/code], [code]@rpc(auth)[/code]). By default, methods are not exposed to networking (and RPCs). </description> </method> <method name="rpc_id" qualifiers="vararg"> diff --git a/modules/enet/doc_classes/ENetMultiplayerPeer.xml b/modules/enet/doc_classes/ENetMultiplayerPeer.xml index 3a37b396a4..79dc77d41d 100644 --- a/modules/enet/doc_classes/ENetMultiplayerPeer.xml +++ b/modules/enet/doc_classes/ENetMultiplayerPeer.xml @@ -81,7 +81,7 @@ <member name="server_relay" type="bool" setter="set_server_relay_enabled" getter="is_server_relay_enabled" default="true"> Enable or disable the server feature that notifies clients of other peers' connection/disconnection, and relays messages between them. When this option is [code]false[/code], clients won't be automatically notified of other peers and won't be able to send them packets through the server. </member> - <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" override="true" enum="MultiplayerPeer.TransferMode" default="2" /> + <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" override="true" enum="TransferMode" default="2" /> </members> <constants> </constants> diff --git a/modules/enet/enet_multiplayer_peer.cpp b/modules/enet/enet_multiplayer_peer.cpp index 7a9a780238..afd31207f6 100644 --- a/modules/enet/enet_multiplayer_peer.cpp +++ b/modules/enet/enet_multiplayer_peer.cpp @@ -41,11 +41,11 @@ int ENetMultiplayerPeer::get_transfer_channel() const { return transfer_channel; } -void ENetMultiplayerPeer::set_transfer_mode(TransferMode p_mode) { +void ENetMultiplayerPeer::set_transfer_mode(Multiplayer::TransferMode p_mode) { transfer_mode = p_mode; } -MultiplayerPeer::TransferMode ENetMultiplayerPeer::get_transfer_mode() const { +Multiplayer::TransferMode ENetMultiplayerPeer::get_transfer_mode() const { return transfer_mode; } @@ -455,15 +455,15 @@ Error ENetMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size channel = SYSCH_MAX + transfer_channel - 1; } else { switch (transfer_mode) { - case TRANSFER_MODE_UNRELIABLE: { + case Multiplayer::TRANSFER_MODE_UNRELIABLE: { packet_flags = ENET_PACKET_FLAG_UNSEQUENCED; channel = SYSCH_UNRELIABLE; } break; - case TRANSFER_MODE_UNRELIABLE_ORDERED: { + case Multiplayer::TRANSFER_MODE_ORDERED: { packet_flags = 0; channel = SYSCH_UNRELIABLE; } break; - case TRANSFER_MODE_RELIABLE: { + case Multiplayer::TRANSFER_MODE_RELIABLE: { packet_flags = ENET_PACKET_FLAG_RELIABLE; channel = SYSCH_RELIABLE; } break; diff --git a/modules/enet/enet_multiplayer_peer.h b/modules/enet/enet_multiplayer_peer.h index 78e280db7c..b5316b8292 100644 --- a/modules/enet/enet_multiplayer_peer.h +++ b/modules/enet/enet_multiplayer_peer.h @@ -32,7 +32,7 @@ #define NETWORKED_MULTIPLAYER_ENET_H #include "core/crypto/crypto.h" -#include "core/io/multiplayer_peer.h" +#include "core/multiplayer/multiplayer_peer.h" #include "enet_connection.h" #include <enet/enet.h> @@ -66,7 +66,7 @@ private: int target_peer = 0; int transfer_channel = 0; - TransferMode transfer_mode = TRANSFER_MODE_RELIABLE; + Multiplayer::TransferMode transfer_mode = Multiplayer::TRANSFER_MODE_RELIABLE; bool refuse_connections = false; bool server_relay = true; @@ -104,8 +104,8 @@ public: virtual void set_transfer_channel(int p_channel) override; virtual int get_transfer_channel() const override; - virtual void set_transfer_mode(TransferMode p_mode) override; - virtual TransferMode get_transfer_mode() const override; + virtual void set_transfer_mode(Multiplayer::TransferMode p_mode) override; + virtual Multiplayer::TransferMode get_transfer_mode() const override; virtual void set_target_peer(int p_peer) override; virtual int get_packet_peer() const override; diff --git a/modules/gdnative/nativescript/godot_nativescript.cpp b/modules/gdnative/nativescript/godot_nativescript.cpp index 70b14836bf..dadd1a9d10 100644 --- a/modules/gdnative/nativescript/godot_nativescript.cpp +++ b/modules/gdnative/nativescript/godot_nativescript.cpp @@ -127,9 +127,9 @@ void GDAPI godot_nativescript_register_method(void *p_gdnative_handle, const cha E->get().methods.insert(p_function_name, method); if (p_attr.rpc_type != GODOT_METHOD_RPC_MODE_DISABLED) { - MultiplayerAPI::RPCConfig nd; + Multiplayer::RPCConfig nd; nd.name = String(p_name); - nd.rpc_mode = MultiplayerAPI::RPCMode(p_attr.rpc_type); + nd.rpc_mode = Multiplayer::RPCMode(p_attr.rpc_type); E->get().rpc_methods.push_back(nd); } } diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp index 26d3aed702..92ba9bd452 100644 --- a/modules/gdnative/nativescript/nativescript.cpp +++ b/modules/gdnative/nativescript/nativescript.cpp @@ -431,9 +431,9 @@ void NativeScript::get_script_property_list(List<PropertyInfo> *p_list) const { } } -const Vector<MultiplayerAPI::RPCConfig> NativeScript::get_rpc_methods() const { +const Vector<Multiplayer::RPCConfig> NativeScript::get_rpc_methods() const { NativeScriptDesc *script_data = get_script_desc(); - ERR_FAIL_COND_V(!script_data, Vector<MultiplayerAPI::RPCConfig>()); + ERR_FAIL_COND_V(!script_data, Vector<Multiplayer::RPCConfig>()); return script_data->rpc_methods; } @@ -828,7 +828,7 @@ Ref<Script> NativeScriptInstance::get_script() const { return script; } -const Vector<MultiplayerAPI::RPCConfig> NativeScriptInstance::get_rpc_methods() const { +const Vector<Multiplayer::RPCConfig> NativeScriptInstance::get_rpc_methods() const { return script->get_rpc_methods(); } diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h index 777a878660..a7647e8c59 100644 --- a/modules/gdnative/nativescript/nativescript.h +++ b/modules/gdnative/nativescript/nativescript.h @@ -71,7 +71,7 @@ struct NativeScriptDesc { }; Map<StringName, Method> methods; - Vector<MultiplayerAPI::RPCConfig> rpc_methods; + Vector<Multiplayer::RPCConfig> rpc_methods; OrderedHashMap<StringName, Property> properties; Map<StringName, Signal> signals_; // QtCreator doesn't like the name signals StringName base; @@ -175,7 +175,7 @@ public: virtual void get_script_method_list(List<MethodInfo> *p_list) const override; virtual void get_script_property_list(List<PropertyInfo> *p_list) const override; - virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override; + virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const override; String get_class_documentation() const; String get_method_documentation(const StringName &p_method) const; @@ -213,7 +213,7 @@ public: String to_string(bool *r_valid); virtual Ref<Script> get_script() const; - virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const; + virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const; virtual ScriptLanguage *get_language(); diff --git a/modules/gdnative/net/multiplayer_peer_gdnative.cpp b/modules/gdnative/net/multiplayer_peer_gdnative.cpp index 9908ed4533..575d5f5060 100644 --- a/modules/gdnative/net/multiplayer_peer_gdnative.cpp +++ b/modules/gdnative/net/multiplayer_peer_gdnative.cpp @@ -72,14 +72,14 @@ int MultiplayerPeerGDNative::get_transfer_channel() const { return interface->get_transfer_channel(interface->data); } -void MultiplayerPeerGDNative::set_transfer_mode(TransferMode p_mode) { +void MultiplayerPeerGDNative::set_transfer_mode(Multiplayer::TransferMode p_mode) { ERR_FAIL_COND(interface == nullptr); interface->set_transfer_mode(interface->data, (godot_int)p_mode); } -MultiplayerPeer::TransferMode MultiplayerPeerGDNative::get_transfer_mode() const { - ERR_FAIL_COND_V(interface == nullptr, TRANSFER_MODE_UNRELIABLE); - return (TransferMode)interface->get_transfer_mode(interface->data); +Multiplayer::TransferMode MultiplayerPeerGDNative::get_transfer_mode() const { + ERR_FAIL_COND_V(interface == nullptr, Multiplayer::TRANSFER_MODE_UNRELIABLE); + return (Multiplayer::TransferMode)interface->get_transfer_mode(interface->data); } void MultiplayerPeerGDNative::set_target_peer(int p_peer_id) { @@ -124,7 +124,7 @@ MultiplayerPeer::ConnectionStatus MultiplayerPeerGDNative::get_connection_status void MultiplayerPeerGDNative::_bind_methods() { ADD_PROPERTY_DEFAULT("transfer_channel", 0); - ADD_PROPERTY_DEFAULT("transfer_mode", TRANSFER_MODE_UNRELIABLE); + ADD_PROPERTY_DEFAULT("transfer_mode", Multiplayer::TRANSFER_MODE_UNRELIABLE); ADD_PROPERTY_DEFAULT("refuse_new_connections", true); } diff --git a/modules/gdnative/net/multiplayer_peer_gdnative.h b/modules/gdnative/net/multiplayer_peer_gdnative.h index ab084faae6..33e424d284 100644 --- a/modules/gdnative/net/multiplayer_peer_gdnative.h +++ b/modules/gdnative/net/multiplayer_peer_gdnative.h @@ -31,7 +31,7 @@ #ifndef MULTIPLAYER_PEER_GDNATIVE_H #define MULTIPLAYER_PEER_GDNATIVE_H -#include "core/io/multiplayer_peer.h" +#include "core/multiplayer/multiplayer_peer.h" #include "modules/gdnative/gdnative.h" #include "modules/gdnative/include/net/godot_net.h" @@ -58,8 +58,8 @@ public: /* Specific to MultiplayerPeer */ virtual void set_transfer_channel(int p_channel) override; virtual int get_transfer_channel() const override; - virtual void set_transfer_mode(TransferMode p_mode) override; - virtual TransferMode get_transfer_mode() const override; + virtual void set_transfer_mode(Multiplayer::TransferMode p_mode) override; + virtual Multiplayer::TransferMode get_transfer_mode() const override; virtual void set_target_peer(int p_peer_id) override; virtual int get_packet_peer() const override; diff --git a/modules/gdnative/pluginscript/pluginscript_instance.cpp b/modules/gdnative/pluginscript/pluginscript_instance.cpp index ed1c0af3ed..feae81397e 100644 --- a/modules/gdnative/pluginscript/pluginscript_instance.cpp +++ b/modules/gdnative/pluginscript/pluginscript_instance.cpp @@ -100,7 +100,7 @@ String PluginScriptInstance::to_string(bool *r_valid) { return str_ret; } -const Vector<MultiplayerAPI::RPCConfig> PluginScriptInstance::get_rpc_methods() const { +const Vector<Multiplayer::RPCConfig> PluginScriptInstance::get_rpc_methods() const { return _script->get_rpc_methods(); } diff --git a/modules/gdnative/pluginscript/pluginscript_instance.h b/modules/gdnative/pluginscript/pluginscript_instance.h index 25b62ae8ab..bdae265db2 100644 --- a/modules/gdnative/pluginscript/pluginscript_instance.h +++ b/modules/gdnative/pluginscript/pluginscript_instance.h @@ -71,7 +71,7 @@ public: void set_path(const String &p_path); - virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const; + virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const; virtual void refcount_incremented(); virtual bool refcount_decremented(); diff --git a/modules/gdnative/pluginscript/pluginscript_script.cpp b/modules/gdnative/pluginscript/pluginscript_script.cpp index 5380858582..2b4ceda49d 100644 --- a/modules/gdnative/pluginscript/pluginscript_script.cpp +++ b/modules/gdnative/pluginscript/pluginscript_script.cpp @@ -334,9 +334,9 @@ Error PluginScript::reload(bool p_keep_state) { // rpc_mode is passed as an optional field and is not part of MethodInfo Variant var = v["rpc_mode"]; if (var != Variant()) { - MultiplayerAPI::RPCConfig nd; + Multiplayer::RPCConfig nd; nd.name = mi.name; - nd.rpc_mode = MultiplayerAPI::RPCMode(int(var)); + nd.rpc_mode = Multiplayer::RPCMode(int(var)); // TODO Transfer Channel if (_rpc_methods.find(nd) == -1) { _rpc_methods.push_back(nd); @@ -345,7 +345,7 @@ Error PluginScript::reload(bool p_keep_state) { } // Sort so we are 100% that they are always the same. - _rpc_methods.sort_custom<MultiplayerAPI::SortRPCConfig>(); + _rpc_methods.sort_custom<Multiplayer::SortRPCConfig>(); Array *signals = (Array *)&manifest.signals; for (int i = 0; i < signals->size(); ++i) { @@ -484,7 +484,7 @@ int PluginScript::get_member_line(const StringName &p_member) const { return -1; } -const Vector<MultiplayerAPI::RPCConfig> PluginScript::get_rpc_methods() const { +const Vector<Multiplayer::RPCConfig> PluginScript::get_rpc_methods() const { return _rpc_methods; } diff --git a/modules/gdnative/pluginscript/pluginscript_script.h b/modules/gdnative/pluginscript/pluginscript_script.h index 838195147f..1a12a130d1 100644 --- a/modules/gdnative/pluginscript/pluginscript_script.h +++ b/modules/gdnative/pluginscript/pluginscript_script.h @@ -61,7 +61,7 @@ private: Map<StringName, PropertyInfo> _properties_info; Map<StringName, MethodInfo> _signals_info; Map<StringName, MethodInfo> _methods_info; - Vector<MultiplayerAPI::RPCConfig> _rpc_methods; + Vector<Multiplayer::RPCConfig> _rpc_methods; Set<Object *> _instances; //exported members @@ -136,7 +136,7 @@ public: virtual int get_member_line(const StringName &p_member) const override; - virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override; + virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const override; PluginScript(); void init(PluginScriptLanguage *language); diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 7943cf7469..5409b3ff79 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -900,7 +900,7 @@ void GDScript::get_members(Set<StringName> *p_members) { } } -const Vector<MultiplayerAPI::RPCConfig> GDScript::get_rpc_methods() const { +const Vector<Multiplayer::RPCConfig> GDScript::get_rpc_methods() const { return rpc_functions; } @@ -1164,8 +1164,8 @@ void GDScript::_init_rpc_methods_properties() { while (cscript) { // RPC Methods for (Map<StringName, GDScriptFunction *>::Element *E = cscript->member_functions.front(); E; E = E->next()) { - MultiplayerAPI::RPCConfig config = E->get()->get_rpc_config(); - if (config.rpc_mode != MultiplayerAPI::RPC_MODE_DISABLED) { + Multiplayer::RPCConfig config = E->get()->get_rpc_config(); + if (config.rpc_mode != Multiplayer::RPC_MODE_DISABLED) { config.name = E->get()->get_name(); if (rpc_functions.find(config) == -1) { rpc_functions.push_back(config); @@ -1185,7 +1185,7 @@ void GDScript::_init_rpc_methods_properties() { } // Sort so we are 100% that they are always the same. - rpc_functions.sort_custom<MultiplayerAPI::SortRPCConfig>(); + rpc_functions.sort_custom<Multiplayer::SortRPCConfig>(); } GDScript::~GDScript() { @@ -1541,7 +1541,7 @@ ScriptLanguage *GDScriptInstance::get_language() { return GDScriptLanguage::get_singleton(); } -const Vector<MultiplayerAPI::RPCConfig> GDScriptInstance::get_rpc_methods() const { +const Vector<Multiplayer::RPCConfig> GDScriptInstance::get_rpc_methods() const { return script->get_rpc_methods(); } diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 24809ad5fd..a6fd7b3b5d 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -85,7 +85,7 @@ class GDScript : public Script { Map<StringName, MemberInfo> member_indices; //members are just indices to the instantiated script. Map<StringName, Ref<GDScript>> subclasses; Map<StringName, Vector<StringName>> _signals; - Vector<MultiplayerAPI::RPCConfig> rpc_functions; + Vector<Multiplayer::RPCConfig> rpc_functions; #ifdef TOOLS_ENABLED @@ -245,7 +245,7 @@ public: virtual void get_constants(Map<StringName, Variant> *p_constants) override; virtual void get_members(Set<StringName> *p_members) override; - virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override; + virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const override; #ifdef TOOLS_ENABLED virtual bool is_placeholder_fallback_enabled() const override { return placeholder_fallback_enabled; } @@ -298,7 +298,7 @@ public: void reload_members(); - virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const; + virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const; GDScriptInstance(); ~GDScriptInstance(); diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index 5958326315..bed67b55f0 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -155,7 +155,7 @@ void GDScriptByteCodeGenerator::end_parameters() { function->default_arguments.reverse(); } -void GDScriptByteCodeGenerator::write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, MultiplayerAPI::RPCConfig p_rpc_config, const GDScriptDataType &p_return_type) { +void GDScriptByteCodeGenerator::write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, Multiplayer::RPCConfig p_rpc_config, const GDScriptDataType &p_return_type) { function = memnew(GDScriptFunction); debug_stack = EngineDebugger::is_active(); diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h index 3d6fb291ad..ce1a043b28 100644 --- a/modules/gdscript/gdscript_byte_codegen.h +++ b/modules/gdscript/gdscript_byte_codegen.h @@ -419,7 +419,7 @@ public: virtual void start_block() override; virtual void end_block() override; - virtual void write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, MultiplayerAPI::RPCConfig p_rpc_config, const GDScriptDataType &p_return_type) override; + virtual void write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, Multiplayer::RPCConfig p_rpc_config, const GDScriptDataType &p_return_type) override; virtual GDScriptFunction *write_end() override; #ifdef DEBUG_ENABLED diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h index ecc86c37f3..7713d13bc8 100644 --- a/modules/gdscript/gdscript_codegen.h +++ b/modules/gdscript/gdscript_codegen.h @@ -31,7 +31,7 @@ #ifndef GDSCRIPT_CODEGEN #define GDSCRIPT_CODEGEN -#include "core/io/multiplayer_api.h" +#include "core/multiplayer/multiplayer.h" #include "core/string/string_name.h" #include "core/variant/variant.h" #include "gdscript_function.h" @@ -80,7 +80,7 @@ public: virtual void start_block() = 0; virtual void end_block() = 0; - virtual void write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, MultiplayerAPI::RPCConfig p_rpc_config, const GDScriptDataType &p_return_type) = 0; + virtual void write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, Multiplayer::RPCConfig p_rpc_config, const GDScriptDataType &p_return_type) = 0; virtual GDScriptFunction *write_end() = 0; #ifdef DEBUG_ENABLED diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index e5cbcc545f..736f6eae79 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -1857,7 +1857,7 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ StringName func_name; bool is_static = false; - MultiplayerAPI::RPCConfig rpc_config; + Multiplayer::RPCConfig rpc_config; GDScriptDataType return_type; return_type.has_type = true; return_type.kind = GDScriptDataType::BUILTIN; @@ -2086,7 +2086,7 @@ Error GDScriptCompiler::_parse_setter_getter(GDScript *p_script, const GDScriptP return_type = _gdtype_from_datatype(p_variable->get_datatype(), p_script); } - codegen.generator->write_start(p_script, func_name, false, MultiplayerAPI::RPCConfig(), return_type); + codegen.generator->write_start(p_script, func_name, false, Multiplayer::RPCConfig(), return_type); if (p_is_setter) { uint32_t par_addr = codegen.generator->add_parameter(p_variable->setter_parameter->name, false, _gdtype_from_datatype(p_variable->get_datatype())); diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h index 87d8c03494..b21cb47910 100644 --- a/modules/gdscript/gdscript_function.h +++ b/modules/gdscript/gdscript_function.h @@ -468,7 +468,7 @@ private: int _initial_line = 0; bool _static = false; - MultiplayerAPI::RPCConfig rpc_config; + Multiplayer::RPCConfig rpc_config; GDScript *_script = nullptr; @@ -588,7 +588,7 @@ public: void disassemble(const Vector<String> &p_code_lines) const; #endif - _FORCE_INLINE_ MultiplayerAPI::RPCConfig get_rpc_config() const { return rpc_config; } + _FORCE_INLINE_ Multiplayer::RPCConfig get_rpc_config() const { return rpc_config; } GDScriptFunction(); ~GDScriptFunction(); }; diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index f4c721e00a..64a393f90c 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -133,7 +133,7 @@ GDScriptParser::GDScriptParser() { register_annotation(MethodInfo("@export_flags_3d_physics"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_PHYSICS, Variant::INT>); register_annotation(MethodInfo("@export_flags_3d_navigation"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_NAVIGATION, Variant::INT>); // Networking. - register_annotation(MethodInfo("@rpc", { Variant::STRING, "mode" }, { Variant::STRING, "sync" }, { Variant::STRING, "transfer_mode" }, { Variant::INT, "transfer_channel" }), AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<MultiplayerAPI::RPC_MODE_AUTHORITY>, 4, true); + register_annotation(MethodInfo("@rpc", { Variant::STRING, "mode" }, { Variant::STRING, "sync" }, { Variant::STRING, "transfer_mode" }, { Variant::INT, "transfer_channel" }), AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<Multiplayer::RPC_MODE_AUTHORITY>, 4, true); // TODO: Warning annotations. } @@ -3393,11 +3393,11 @@ bool GDScriptParser::warning_annotations(const AnnotationNode *p_annotation, Nod ERR_FAIL_V_MSG(false, "Not implemented."); } -template <MultiplayerAPI::RPCMode t_mode> +template <Multiplayer::RPCMode t_mode> bool GDScriptParser::network_annotations(const AnnotationNode *p_annotation, Node *p_node) { ERR_FAIL_COND_V_MSG(p_node->type != Node::VARIABLE && p_node->type != Node::FUNCTION, false, vformat(R"("%s" annotation can only be applied to variables and functions.)", p_annotation->name)); - MultiplayerAPI::RPCConfig rpc_config; + Multiplayer::RPCConfig rpc_config; rpc_config.rpc_mode = t_mode; if (p_annotation->resolved_arguments.size()) { int last = p_annotation->resolved_arguments.size() - 1; @@ -3412,19 +3412,19 @@ bool GDScriptParser::network_annotations(const AnnotationNode *p_annotation, Nod for (int i = last; i >= 0; i--) { String mode = p_annotation->resolved_arguments[i].operator String(); if (mode == "any") { - rpc_config.rpc_mode = MultiplayerAPI::RPC_MODE_ANY; + rpc_config.rpc_mode = Multiplayer::RPC_MODE_ANY; } else if (mode == "auth") { - rpc_config.rpc_mode = MultiplayerAPI::RPC_MODE_AUTHORITY; + rpc_config.rpc_mode = Multiplayer::RPC_MODE_AUTHORITY; } else if (mode == "sync") { rpc_config.sync = true; } else if (mode == "nosync") { rpc_config.sync = false; } else if (mode == "reliable") { - rpc_config.transfer_mode = MultiplayerPeer::TRANSFER_MODE_RELIABLE; + rpc_config.transfer_mode = Multiplayer::TRANSFER_MODE_RELIABLE; } else if (mode == "unreliable") { - rpc_config.transfer_mode = MultiplayerPeer::TRANSFER_MODE_UNRELIABLE; + rpc_config.transfer_mode = Multiplayer::TRANSFER_MODE_UNRELIABLE; } else if (mode == "ordered") { - rpc_config.transfer_mode = MultiplayerPeer::TRANSFER_MODE_UNRELIABLE_ORDERED; + rpc_config.transfer_mode = Multiplayer::TRANSFER_MODE_ORDERED; } else { push_error(R"(Invalid RPC argument. Must be one of: 'sync'/'nosync' (local calls), 'any'/'auth' (permission), 'reliable'/'unreliable'/'ordered' (transfer mode).)", p_annotation); } @@ -3433,7 +3433,7 @@ bool GDScriptParser::network_annotations(const AnnotationNode *p_annotation, Nod switch (p_node->type) { case Node::FUNCTION: { FunctionNode *function = static_cast<FunctionNode *>(p_node); - if (function->rpc_config.rpc_mode != MultiplayerAPI::RPC_MODE_DISABLED) { + if (function->rpc_config.rpc_mode != Multiplayer::RPC_MODE_DISABLED) { push_error(R"(RPC annotations can only be used once per function.)", p_annotation); return false; } diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 0bce8d7ddd..4902f0d4a6 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -31,8 +31,8 @@ #ifndef GDSCRIPT_PARSER_H #define GDSCRIPT_PARSER_H -#include "core/io/multiplayer_api.h" #include "core/io/resource.h" +#include "core/multiplayer/multiplayer.h" #include "core/object/ref_counted.h" #include "core/object/script_language.h" #include "core/string/string_name.h" @@ -729,7 +729,7 @@ public: SuiteNode *body = nullptr; bool is_static = false; bool is_coroutine = false; - MultiplayerAPI::RPCConfig rpc_config; + Multiplayer::RPCConfig rpc_config; MethodInfo info; LambdaNode *source_lambda = nullptr; #ifdef TOOLS_ENABLED @@ -1340,7 +1340,7 @@ private: template <PropertyHint t_hint, Variant::Type t_type> bool export_annotations(const AnnotationNode *p_annotation, Node *p_target); bool warning_annotations(const AnnotationNode *p_annotation, Node *p_target); - template <MultiplayerAPI::RPCMode t_mode> + template <Multiplayer::RPCMode t_mode> bool network_annotations(const AnnotationNode *p_annotation, Node *p_target); // Statements. Node *parse_statement(); diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 978093b7d5..98519707a9 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -2124,7 +2124,7 @@ bool CSharpInstance::refcount_decremented() { return ref_dying; } -const Vector<MultiplayerAPI::RPCConfig> CSharpInstance::get_rpc_methods() const { +const Vector<Multiplayer::RPCConfig> CSharpInstance::get_rpc_methods() const { return script->get_rpc_methods(); } @@ -3034,13 +3034,13 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) { Vector<GDMonoMethod *> methods = top->get_all_methods(); for (int i = 0; i < methods.size(); i++) { if (!methods[i]->is_static()) { - MultiplayerAPI::RPCMode mode = p_script->_member_get_rpc_mode(methods[i]); - if (MultiplayerAPI::RPC_MODE_DISABLED != mode) { - MultiplayerAPI::RPCConfig nd; + Multiplayer::RPCMode mode = p_script->_member_get_rpc_mode(methods[i]); + if (Multiplayer::RPC_MODE_DISABLED != mode) { + Multiplayer::RPCConfig nd; nd.name = methods[i]->get_name(); nd.rpc_mode = mode; // TODO Transfer mode, channel - nd.transfer_mode = MultiplayerPeer::TRANSFER_MODE_RELIABLE; + nd.transfer_mode = Multiplayer::TRANSFER_MODE_RELIABLE; nd.channel = 0; if (-1 == p_script->rpc_functions.find(nd)) { p_script->rpc_functions.push_back(nd); @@ -3054,7 +3054,7 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) { } // Sort so we are 100% that they are always the same. - p_script->rpc_functions.sort_custom<MultiplayerAPI::SortRPCConfig>(); + p_script->rpc_functions.sort_custom<Multiplayer::SortRPCConfig>(); p_script->load_script_signals(p_script->script_class, p_script->native); } @@ -3464,18 +3464,18 @@ int CSharpScript::get_member_line(const StringName &p_member) const { return -1; } -MultiplayerAPI::RPCMode CSharpScript::_member_get_rpc_mode(IMonoClassMember *p_member) const { +Multiplayer::RPCMode CSharpScript::_member_get_rpc_mode(IMonoClassMember *p_member) const { if (p_member->has_attribute(CACHED_CLASS(RemoteAttribute))) { - return MultiplayerAPI::RPC_MODE_ANY; + return Multiplayer::RPC_MODE_ANY; } if (p_member->has_attribute(CACHED_CLASS(PuppetAttribute))) { - return MultiplayerAPI::RPC_MODE_AUTHORITY; + return Multiplayer::RPC_MODE_AUTHORITY; } - return MultiplayerAPI::RPC_MODE_DISABLED; + return Multiplayer::RPC_MODE_DISABLED; } -const Vector<MultiplayerAPI::RPCConfig> CSharpScript::get_rpc_methods() const { +const Vector<Multiplayer::RPCConfig> CSharpScript::get_rpc_methods() const { return rpc_functions; } diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index 4552f376d0..e3bbb20dec 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -136,7 +136,7 @@ private: Map<StringName, EventSignal> event_signals; bool signals_invalidated = true; - Vector<MultiplayerAPI::RPCConfig> rpc_functions; + Vector<Multiplayer::RPCConfig> rpc_functions; #ifdef TOOLS_ENABLED List<PropertyInfo> exported_members_cache; // members_cache @@ -179,7 +179,7 @@ private: static void update_script_class_info(Ref<CSharpScript> p_script); static void initialize_for_managed_type(Ref<CSharpScript> p_script, GDMonoClass *p_class, GDMonoClass *p_native); - MultiplayerAPI::RPCMode _member_get_rpc_mode(IMonoClassMember *p_member) const; + Multiplayer::RPCMode _member_get_rpc_mode(IMonoClassMember *p_member) const; protected: static void _bind_methods(); @@ -234,7 +234,7 @@ public: int get_member_line(const StringName &p_member) const override; - const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override; + const Vector<Multiplayer::RPCConfig> get_rpc_methods() const override; #ifdef TOOLS_ENABLED bool is_placeholder_fallback_enabled() const override { return placeholder_fallback_enabled; } @@ -311,7 +311,7 @@ public: void refcount_incremented() override; bool refcount_decremented() override; - const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override; + const Vector<Multiplayer::RPCConfig> get_rpc_methods() const override; void notification(int p_notification) override; void _call_notification(int p_notification); diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index 142419f90a..4d5f3420b8 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -955,7 +955,7 @@ bool VisualScript::are_subnodes_edited() const { } #endif -const Vector<MultiplayerAPI::RPCConfig> VisualScript::get_rpc_methods() const { +const Vector<Multiplayer::RPCConfig> VisualScript::get_rpc_methods() const { return rpc_functions; } @@ -1022,11 +1022,11 @@ void VisualScript::_set_data(const Dictionary &p_data) { if (functions[E].func_id >= 0 && nodes.has(functions[E].func_id)) { Ref<VisualScriptFunction> vsf = nodes[functions[E].func_id].node; if (vsf.is_valid()) { - if (vsf->get_rpc_mode() != MultiplayerAPI::RPC_MODE_DISABLED) { - MultiplayerAPI::RPCConfig nd; + if (vsf->get_rpc_mode() != Multiplayer::RPC_MODE_DISABLED) { + Multiplayer::RPCConfig nd; nd.name = E; nd.rpc_mode = vsf->get_rpc_mode(); - nd.transfer_mode = MultiplayerPeer::TRANSFER_MODE_RELIABLE; // TODO + nd.transfer_mode = Multiplayer::TRANSFER_MODE_RELIABLE; // TODO if (rpc_functions.find(nd) == -1) { rpc_functions.push_back(nd); } @@ -1036,7 +1036,7 @@ void VisualScript::_set_data(const Dictionary &p_data) { } // Sort so we are 100% that they are always the same. - rpc_functions.sort_custom<MultiplayerAPI::SortRPCConfig>(); + rpc_functions.sort_custom<Multiplayer::SortRPCConfig>(); } Dictionary VisualScript::_get_data() const { @@ -1833,7 +1833,7 @@ Ref<Script> VisualScriptInstance::get_script() const { return script; } -const Vector<MultiplayerAPI::RPCConfig> VisualScriptInstance::get_rpc_methods() const { +const Vector<Multiplayer::RPCConfig> VisualScriptInstance::get_rpc_methods() const { return script->get_rpc_methods(); } diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h index 932ebeb27f..39cef8f68b 100644 --- a/modules/visual_script/visual_script.h +++ b/modules/visual_script/visual_script.h @@ -234,7 +234,7 @@ private: HashMap<StringName, Function> functions; HashMap<StringName, Variable> variables; Map<StringName, Vector<Argument>> custom_signals; - Vector<MultiplayerAPI::RPCConfig> rpc_functions; + Vector<Multiplayer::RPCConfig> rpc_functions; Map<Object *, VisualScriptInstance *> instances; @@ -362,7 +362,7 @@ public: virtual int get_member_line(const StringName &p_member) const override; - virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override; + virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const override; #ifdef TOOLS_ENABLED virtual bool are_subnodes_edited() const; @@ -443,7 +443,7 @@ public: virtual ScriptLanguage *get_language(); - virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const; + virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const; VisualScriptInstance(); ~VisualScriptInstance(); diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp index 44fc91d8f5..ef77c0cef3 100644 --- a/modules/visual_script/visual_script_nodes.cpp +++ b/modules/visual_script/visual_script_nodes.cpp @@ -90,7 +90,7 @@ bool VisualScriptFunction::_set(const StringName &p_name, const Variant &p_value } if (p_name == "rpc/mode") { - rpc_mode = MultiplayerAPI::RPCMode(int(p_value)); + rpc_mode = Multiplayer::RPCMode(int(p_value)); return true; } @@ -261,11 +261,11 @@ int VisualScriptFunction::get_argument_count() const { return arguments.size(); } -void VisualScriptFunction::set_rpc_mode(MultiplayerAPI::RPCMode p_mode) { +void VisualScriptFunction::set_rpc_mode(Multiplayer::RPCMode p_mode) { rpc_mode = p_mode; } -MultiplayerAPI::RPCMode VisualScriptFunction::get_rpc_mode() const { +Multiplayer::RPCMode VisualScriptFunction::get_rpc_mode() const { return rpc_mode; } @@ -311,14 +311,14 @@ void VisualScriptFunction::reset_state() { stack_size = 256; stack_less = false; sequenced = true; - rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; + rpc_mode = Multiplayer::RPC_MODE_DISABLED; } VisualScriptFunction::VisualScriptFunction() { stack_size = 256; stack_less = false; sequenced = true; - rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; + rpc_mode = Multiplayer::RPC_MODE_DISABLED; } void VisualScriptFunction::set_stack_less(bool p_enable) { diff --git a/modules/visual_script/visual_script_nodes.h b/modules/visual_script/visual_script_nodes.h index 35d9b0b4fe..bf2d8e9683 100644 --- a/modules/visual_script/visual_script_nodes.h +++ b/modules/visual_script/visual_script_nodes.h @@ -49,7 +49,7 @@ class VisualScriptFunction : public VisualScriptNode { bool stack_less; int stack_size; - MultiplayerAPI::RPCMode rpc_mode; + Multiplayer::RPCMode rpc_mode; bool sequenced; protected: @@ -96,8 +96,8 @@ public: void set_return_type(Variant::Type p_type); Variant::Type get_return_type() const; - void set_rpc_mode(MultiplayerAPI::RPCMode p_mode); - MultiplayerAPI::RPCMode get_rpc_mode() const; + void set_rpc_mode(Multiplayer::RPCMode p_mode); + Multiplayer::RPCMode get_rpc_mode() const; virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; diff --git a/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml index c53af22ae1..3f137ab7b3 100644 --- a/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml +++ b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml @@ -56,7 +56,7 @@ Initialize the multiplayer peer with the given [code]peer_id[/code] (must be between 1 and 2147483647). If [code]server_compatibilty[/code] is [code]false[/code] (default), the multiplayer peer will be immediately in state [constant MultiplayerPeer.CONNECTION_CONNECTED] and [signal MultiplayerPeer.connection_succeeded] will not be emitted. If [code]server_compatibilty[/code] is [code]true[/code] the peer will suppress all [signal MultiplayerPeer.peer_connected] signals until a peer with id [constant MultiplayerPeer.TARGET_PEER_SERVER] connects and then emit [signal MultiplayerPeer.connection_succeeded]. After that the signal [signal MultiplayerPeer.peer_connected] will be emitted for every already connected peer, and any new peer that might connect. If the server peer disconnects after that, signal [signal MultiplayerPeer.server_disconnected] will be emitted and state will become [constant MultiplayerPeer.CONNECTION_CONNECTED]. - You can optionally specify a [code]channels_config[/code] array of [enum MultiplayerPeer.TransferMode] which will be used to create extra channels (WebRTC only supports one transfer mode per channel). + You can optionally specify a [code]channels_config[/code] array of [enum TransferMode] which will be used to create extra channels (WebRTC only supports one transfer mode per channel). </description> </method> <method name="remove_peer"> @@ -69,7 +69,7 @@ </methods> <members> <member name="refuse_new_connections" type="bool" setter="set_refuse_new_connections" getter="is_refusing_new_connections" override="true" default="false" /> - <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" override="true" enum="MultiplayerPeer.TransferMode" default="2" /> + <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" override="true" enum="TransferMode" default="2" /> </members> <constants> </constants> diff --git a/modules/webrtc/webrtc_multiplayer_peer.cpp b/modules/webrtc/webrtc_multiplayer_peer.cpp index 95c8c13449..d60d694df1 100644 --- a/modules/webrtc/webrtc_multiplayer_peer.cpp +++ b/modules/webrtc/webrtc_multiplayer_peer.cpp @@ -51,11 +51,11 @@ int WebRTCMultiplayerPeer::get_transfer_channel() const { return transfer_channel; } -void WebRTCMultiplayerPeer::set_transfer_mode(TransferMode p_mode) { +void WebRTCMultiplayerPeer::set_transfer_mode(Multiplayer::TransferMode p_mode) { transfer_mode = p_mode; } -MultiplayerPeer::TransferMode WebRTCMultiplayerPeer::get_transfer_mode() const { +Multiplayer::TransferMode WebRTCMultiplayerPeer::get_transfer_mode() const { return transfer_mode; } @@ -204,7 +204,7 @@ Error WebRTCMultiplayerPeer::initialize(int p_self_id, bool p_server_compat, Arr ERR_FAIL_COND_V(p_self_id < 1 || p_self_id > ~(1 << 31), ERR_INVALID_PARAMETER); channels_config.clear(); for (int i = 0; i < p_channels_config.size(); i++) { - ERR_FAIL_COND_V_MSG(p_channels_config[i].get_type() != Variant::INT, ERR_INVALID_PARAMETER, "The 'channels_config' array must contain only enum values from 'MultiplayerPeer.TransferMode'"); + ERR_FAIL_COND_V_MSG(p_channels_config[i].get_type() != Variant::INT, ERR_INVALID_PARAMETER, "The 'channels_config' array must contain only enum values from 'MultiplayerPeer.Multiplayer::TransferMode'"); int mode = p_channels_config[i].operator int(); // Initialize data channel configurations. Dictionary cfg; @@ -213,17 +213,17 @@ Error WebRTCMultiplayerPeer::initialize(int p_self_id, bool p_server_compat, Arr cfg["ordered"] = true; switch (mode) { - case TRANSFER_MODE_UNRELIABLE_ORDERED: + case Multiplayer::TRANSFER_MODE_ORDERED: cfg["maxPacketLifetime"] = 1; break; - case TRANSFER_MODE_UNRELIABLE: + case Multiplayer::TRANSFER_MODE_UNRELIABLE: cfg["maxPacketLifetime"] = 1; cfg["ordered"] = false; break; - case TRANSFER_MODE_RELIABLE: + case Multiplayer::TRANSFER_MODE_RELIABLE: break; default: - ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, vformat("The 'channels_config' array must contain only enum values from 'MultiplayerPeer.TransferMode'. Got: %d", mode)); + ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, vformat("The 'channels_config' array must contain only enum values from 'MultiplayerPeer.Multiplayer::TransferMode'. Got: %d", mode)); } channels_config.push_back(cfg); } @@ -355,13 +355,13 @@ Error WebRTCMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_si int ch = transfer_channel; if (ch == 0) { switch (transfer_mode) { - case TRANSFER_MODE_RELIABLE: + case Multiplayer::TRANSFER_MODE_RELIABLE: ch = CH_RELIABLE; break; - case TRANSFER_MODE_UNRELIABLE_ORDERED: + case Multiplayer::TRANSFER_MODE_ORDERED: ch = CH_ORDERED; break; - case TRANSFER_MODE_UNRELIABLE: + case Multiplayer::TRANSFER_MODE_UNRELIABLE: ch = CH_UNRELIABLE; break; } diff --git a/modules/webrtc/webrtc_multiplayer_peer.h b/modules/webrtc/webrtc_multiplayer_peer.h index ef4fe1678c..80a6491492 100644 --- a/modules/webrtc/webrtc_multiplayer_peer.h +++ b/modules/webrtc/webrtc_multiplayer_peer.h @@ -31,7 +31,7 @@ #ifndef WEBRTC_MULTIPLAYER_H #define WEBRTC_MULTIPLAYER_H -#include "core/io/multiplayer_peer.h" +#include "core/multiplayer/multiplayer_peer.h" #include "webrtc_peer_connection.h" class WebRTCMultiplayerPeer : public MultiplayerPeer { @@ -68,7 +68,7 @@ private: bool refuse_connections = false; ConnectionStatus connection_status = CONNECTION_DISCONNECTED; int transfer_channel = 0; - TransferMode transfer_mode = TRANSFER_MODE_RELIABLE; + Multiplayer::TransferMode transfer_mode = Multiplayer::TRANSFER_MODE_RELIABLE; int next_packet_peer = 0; bool server_compat = false; @@ -99,8 +99,8 @@ public: // MultiplayerPeer void set_transfer_channel(int p_channel) override; int get_transfer_channel() const override; - void set_transfer_mode(TransferMode p_mode) override; - TransferMode get_transfer_mode() const override; + void set_transfer_mode(Multiplayer::TransferMode p_mode) override; + Multiplayer::TransferMode get_transfer_mode() const override; void set_target_peer(int p_peer_id) override; int get_unique_id() const override; diff --git a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml index cd41e9a1fb..ac63379d71 100644 --- a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml +++ b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml @@ -32,7 +32,7 @@ </methods> <members> <member name="refuse_new_connections" type="bool" setter="set_refuse_new_connections" getter="is_refusing_new_connections" override="true" default="false" /> - <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" override="true" enum="MultiplayerPeer.TransferMode" default="2" /> + <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" override="true" enum="TransferMode" default="2" /> </members> <signals> <signal name="peer_packet"> diff --git a/modules/websocket/websocket_multiplayer_peer.cpp b/modules/websocket/websocket_multiplayer_peer.cpp index 163cc7706b..7464cf2bf5 100644 --- a/modules/websocket/websocket_multiplayer_peer.cpp +++ b/modules/websocket/websocket_multiplayer_peer.cpp @@ -113,13 +113,13 @@ int WebSocketMultiplayerPeer::get_transfer_channel() const { return 0; } -void WebSocketMultiplayerPeer::set_transfer_mode(TransferMode p_mode) { +void WebSocketMultiplayerPeer::set_transfer_mode(Multiplayer::TransferMode p_mode) { // Websocket uses TCP, reliable } -MultiplayerPeer::TransferMode WebSocketMultiplayerPeer::get_transfer_mode() const { +Multiplayer::TransferMode WebSocketMultiplayerPeer::get_transfer_mode() const { // Websocket uses TCP, reliable - return TRANSFER_MODE_RELIABLE; + return Multiplayer::TRANSFER_MODE_RELIABLE; } void WebSocketMultiplayerPeer::set_target_peer(int p_target_peer) { diff --git a/modules/websocket/websocket_multiplayer_peer.h b/modules/websocket/websocket_multiplayer_peer.h index 0fee196f41..d97a599fe9 100644 --- a/modules/websocket/websocket_multiplayer_peer.h +++ b/modules/websocket/websocket_multiplayer_peer.h @@ -32,7 +32,7 @@ #define WEBSOCKET_MULTIPLAYER_PEER_H #include "core/error/error_list.h" -#include "core/io/multiplayer_peer.h" +#include "core/multiplayer/multiplayer_peer.h" #include "core/templates/list.h" #include "websocket_peer.h" @@ -80,8 +80,8 @@ public: /* MultiplayerPeer */ void set_transfer_channel(int p_channel) override; int get_transfer_channel() const override; - void set_transfer_mode(TransferMode p_mode) override; - TransferMode get_transfer_mode() const override; + void set_transfer_mode(Multiplayer::TransferMode p_mode) override; + Multiplayer::TransferMode get_transfer_mode() const override; void set_target_peer(int p_target_peer) override; int get_packet_peer() const override; int get_unique_id() const override; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index f2a2648140..5eab3e472c 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -539,10 +539,10 @@ bool Node::is_network_authority() const { /***** RPC CONFIG ********/ -uint16_t Node::rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_rpc_mode, MultiplayerPeer::TransferMode p_transfer_mode, int p_channel) { +uint16_t Node::rpc_config(const StringName &p_method, Multiplayer::RPCMode p_rpc_mode, Multiplayer::TransferMode p_transfer_mode, int p_channel) { for (int i = 0; i < data.rpc_methods.size(); i++) { if (data.rpc_methods[i].name == p_method) { - MultiplayerAPI::RPCConfig &nd = data.rpc_methods.write[i]; + Multiplayer::RPCConfig &nd = data.rpc_methods.write[i]; nd.rpc_mode = p_rpc_mode; nd.transfer_mode = p_transfer_mode; nd.channel = p_channel; @@ -550,7 +550,7 @@ uint16_t Node::rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_ } } // New method - MultiplayerAPI::RPCConfig nd; + Multiplayer::RPCConfig nd; nd.name = p_method; nd.rpc_mode = p_rpc_mode; nd.transfer_mode = p_transfer_mode; @@ -643,7 +643,7 @@ Variant Node::_rpc_id_bind(const Variant **p_args, int p_argcount, Callable::Cal void Node::rpcp(int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount) { ERR_FAIL_COND(!is_inside_tree()); - get_multiplayer()->rpcp(this, p_peer_id, true, p_method, p_arg, p_argcount); + get_multiplayer()->rpcp(this, p_peer_id, p_method, p_arg, p_argcount); } Ref<MultiplayerAPI> Node::get_multiplayer() const { @@ -664,7 +664,7 @@ void Node::set_custom_multiplayer(Ref<MultiplayerAPI> p_multiplayer) { multiplayer = p_multiplayer; } -Vector<MultiplayerAPI::RPCConfig> Node::get_node_rpc_methods() const { +Vector<Multiplayer::RPCConfig> Node::get_node_rpc_methods() const { return data.rpc_methods; } @@ -2746,7 +2746,7 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("get_multiplayer"), &Node::get_multiplayer); ClassDB::bind_method(D_METHOD("get_custom_multiplayer"), &Node::get_custom_multiplayer); ClassDB::bind_method(D_METHOD("set_custom_multiplayer", "api"), &Node::set_custom_multiplayer); - ClassDB::bind_method(D_METHOD("rpc_config", "method", "rpc_mode", "transfer_mode", "channel"), &Node::rpc_config, DEFVAL(MultiplayerPeer::TRANSFER_MODE_RELIABLE), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("rpc_config", "method", "rpc_mode", "transfer_mode", "channel"), &Node::rpc_config, DEFVAL(Multiplayer::TRANSFER_MODE_RELIABLE), DEFVAL(0)); ClassDB::bind_method(D_METHOD("set_editor_description", "editor_description"), &Node::set_editor_description); ClassDB::bind_method(D_METHOD("get_editor_description"), &Node::get_editor_description); diff --git a/scene/main/node.h b/scene/main/node.h index d0246ebe84..27d6958140 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -128,7 +128,7 @@ private: Node *process_owner = nullptr; int network_authority = 1; // Server by default. - Vector<MultiplayerAPI::RPCConfig> rpc_methods; + Vector<Multiplayer::RPCConfig> rpc_methods; // Variables used to properly sort the node when processing, ignored otherwise. // TODO: Should move all the stuff below to bits. @@ -466,8 +466,8 @@ public: int get_network_authority() const; bool is_network_authority() const; - uint16_t rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_rpc_mode, MultiplayerPeer::TransferMode p_transfer_mode, int p_channel = 0); // config a local method for RPC - Vector<MultiplayerAPI::RPCConfig> get_node_rpc_methods() const; + uint16_t rpc_config(const StringName &p_method, Multiplayer::RPCMode p_rpc_mode, Multiplayer::TransferMode p_transfer_mode, int p_channel = 0); // config a local method for RPC + Vector<Multiplayer::RPCConfig> get_node_rpc_methods() const; void rpc(const StringName &p_method, VARIANT_ARG_LIST); // RPC, honors RPCMode, TransferMode, channel void rpc_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_LIST); // RPC to specific peer(s), honors RPCMode, TransferMode, channel diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index b1b94ae910..19331c1906 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -31,7 +31,7 @@ #ifndef SCENE_TREE_H #define SCENE_TREE_H -#include "core/io/multiplayer_api.h" +#include "core/multiplayer/multiplayer_api.h" #include "core/os/main_loop.h" #include "core/os/thread_safe.h" #include "core/templates/self_list.h" diff --git a/servers/audio/effects/audio_effect_capture.h b/servers/audio/effects/audio_effect_capture.h index 7f50fc4965..bb1d03be8c 100644 --- a/servers/audio/effects/audio_effect_capture.h +++ b/servers/audio/effects/audio_effect_capture.h @@ -34,6 +34,7 @@ #include "core/config/engine.h" #include "core/math/audio_frame.h" #include "core/object/ref_counted.h" +#include "core/templates/ring_buffer.h" #include "core/templates/vector.h" #include "servers/audio/audio_effect.h" #include "servers/audio_server.h" diff --git a/tests/test_object.h b/tests/test_object.h index a18adf31b6..8cb7116a20 100644 --- a/tests/test_object.h +++ b/tests/test_object.h @@ -93,8 +93,8 @@ public: Ref<Script> get_script() const override { return Ref<Script>(); } - const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override { - return Vector<MultiplayerAPI::RPCConfig>(); + const Vector<Multiplayer::RPCConfig> get_rpc_methods() const override { + return Vector<Multiplayer::RPCConfig>(); } ScriptLanguage *get_language() override { return nullptr; |