From 2cf39b97ae326a28015b67221b928e4861380d29 Mon Sep 17 00:00:00 2001 From: Fabio Alessandrelli Date: Tue, 27 Jul 2021 12:06:48 +0200 Subject: [PATCH] [Net] Implement RPC channels in MultiplayerAPI. --- core/io/multiplayer_api.cpp | 8 +- core/io/multiplayer_api.h | 2 +- core/io/multiplayer_peer.cpp | 3 + core/io/multiplayer_peer.h | 2 + doc/classes/MultiplayerAPI.xml | 1 + doc/classes/MultiplayerPeer.xml | 4 + modules/enet/enet_multiplayer_peer.cpp | 39 +++++--- modules/enet/enet_multiplayer_peer.h | 12 ++- modules/gdnative/include/net/godot_net.h | 2 + .../net/multiplayer_peer_gdnative.cpp | 11 +++ .../gdnative/net/multiplayer_peer_gdnative.h | 2 + .../doc_classes/WebRTCMultiplayerPeer.xml | 2 + modules/webrtc/webrtc_multiplayer_peer.cpp | 97 +++++++++++++------ modules/webrtc/webrtc_multiplayer_peer.h | 24 +++-- .../websocket/websocket_multiplayer_peer.cpp | 8 ++ .../websocket/websocket_multiplayer_peer.h | 2 + 16 files changed, 157 insertions(+), 62 deletions(-) diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp index d4f09b2135a7..1c3f23117059 100644 --- a/core/io/multiplayer_api.cpp +++ b/core/io/multiplayer_api.cpp @@ -478,6 +478,7 @@ void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet, packet.write[1] = valid_rpc_checksum; 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_target_peer(p_from); network_peer->put_packet(packet.ptr(), packet.size()); @@ -557,6 +558,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->put_packet(packet.ptr(), packet.size()); @@ -858,6 +860,7 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, const #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) { @@ -996,7 +999,7 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const 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 p_data, int p_to, MultiplayerPeer::TransferMode p_mode) { +Error MultiplayerAPI::send_bytes(Vector p_data, int p_to, MultiplayerPeer::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."); @@ -1007,6 +1010,7 @@ Error MultiplayerAPI::send_bytes(Vector p_data, int p_to, MultiplayerPe memcpy(&packet_cache.write[1], &r[0], p_data.size()); network_peer->set_target_peer(p_to); + network_peer->set_transfer_channel(p_channel); network_peer->set_transfer_mode(p_mode); return network_peer->put_packet(packet_cache.ptr(), p_data.size() + 1); @@ -1066,7 +1070,7 @@ bool MultiplayerAPI::is_object_decoding_allowed() const { 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"), &MultiplayerAPI::send_bytes, DEFVAL(MultiplayerPeer::TARGET_PEER_BROADCAST), DEFVAL(MultiplayerPeer::TRANSFER_MODE_RELIABLE)); + 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("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); diff --git a/core/io/multiplayer_api.h b/core/io/multiplayer_api.h index cc994a9852a7..011bc3dde9c7 100644 --- a/core/io/multiplayer_api.h +++ b/core/io/multiplayer_api.h @@ -132,7 +132,7 @@ public: Node *get_root_node(); void set_network_peer(const Ref &p_peer); Ref get_network_peer() const; - Error send_bytes(Vector p_data, int p_to = MultiplayerPeer::TARGET_PEER_BROADCAST, MultiplayerPeer::TransferMode p_mode = MultiplayerPeer::TRANSFER_MODE_RELIABLE); + Error send_bytes(Vector p_data, int p_to = MultiplayerPeer::TARGET_PEER_BROADCAST, MultiplayerPeer::TransferMode p_mode = MultiplayerPeer::TRANSFER_MODE_RELIABLE, int p_channel = 0); // 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); diff --git a/core/io/multiplayer_peer.cpp b/core/io/multiplayer_peer.cpp index 8b3b1eef8e6e..83cf24d7e36e 100644 --- a/core/io/multiplayer_peer.cpp +++ b/core/io/multiplayer_peer.cpp @@ -54,6 +54,8 @@ uint32_t MultiplayerPeer::generate_unique_id() const { } void MultiplayerPeer::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_transfer_channel", "channel"), &MultiplayerPeer::set_transfer_channel); + ClassDB::bind_method(D_METHOD("get_transfer_channel"), &MultiplayerPeer::get_transfer_channel); ClassDB::bind_method(D_METHOD("set_transfer_mode", "mode"), &MultiplayerPeer::set_transfer_mode); ClassDB::bind_method(D_METHOD("get_transfer_mode"), &MultiplayerPeer::get_transfer_mode); ClassDB::bind_method(D_METHOD("set_target_peer", "id"), &MultiplayerPeer::set_target_peer); @@ -71,6 +73,7 @@ void MultiplayerPeer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_connections"), "set_refuse_new_connections", "is_refusing_new_connections"); 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); diff --git a/core/io/multiplayer_peer.h b/core/io/multiplayer_peer.h index 91a3ad7954b3..7ca4e7930b2c 100644 --- a/core/io/multiplayer_peer.h +++ b/core/io/multiplayer_peer.h @@ -56,6 +56,8 @@ public: CONNECTION_CONNECTED, }; + 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_target_peer(int p_peer_id) = 0; diff --git a/doc/classes/MultiplayerAPI.xml b/doc/classes/MultiplayerAPI.xml index 104f649921e7..552e0fce4c05 100644 --- a/doc/classes/MultiplayerAPI.xml +++ b/doc/classes/MultiplayerAPI.xml @@ -61,6 +61,7 @@ + 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. diff --git a/doc/classes/MultiplayerPeer.xml b/doc/classes/MultiplayerPeer.xml index 88cd058c51c0..adaa359168fa 100644 --- a/doc/classes/MultiplayerPeer.xml +++ b/doc/classes/MultiplayerPeer.xml @@ -55,6 +55,10 @@ If [code]true[/code], this [MultiplayerPeer] refuses new connections. + + 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. + The manner in which to send packets to the [code]target_peer[/code]. See [enum TransferMode]. diff --git a/modules/enet/enet_multiplayer_peer.cpp b/modules/enet/enet_multiplayer_peer.cpp index 28b6bb035aad..aa0e09bcde5c 100644 --- a/modules/enet/enet_multiplayer_peer.cpp +++ b/modules/enet/enet_multiplayer_peer.cpp @@ -33,6 +33,14 @@ #include "core/io/marshalls.h" #include "core/os/os.h" +void ENetMultiplayerPeer::set_transfer_channel(int p_channel) { + transfer_channel = p_channel; +} + +int ENetMultiplayerPeer::get_transfer_channel() const { + return transfer_channel; +} + void ENetMultiplayerPeer::set_transfer_mode(TransferMode p_mode) { transfer_mode = p_mode; } @@ -441,20 +449,23 @@ Error ENetMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size int packet_flags = 0; int channel = SYSCH_RELIABLE; - - switch (transfer_mode) { - case TRANSFER_MODE_UNRELIABLE: { - packet_flags = ENET_PACKET_FLAG_UNSEQUENCED; - channel = SYSCH_UNRELIABLE; - } break; - case TRANSFER_MODE_UNRELIABLE_ORDERED: { - packet_flags = 0; - channel = SYSCH_UNRELIABLE; - } break; - case TRANSFER_MODE_RELIABLE: { - packet_flags = ENET_PACKET_FLAG_RELIABLE; - channel = SYSCH_RELIABLE; - } break; + if (transfer_channel > 0) { + channel = SYSCH_MAX + transfer_channel - 1; + } else { + switch (transfer_mode) { + case TRANSFER_MODE_UNRELIABLE: { + packet_flags = ENET_PACKET_FLAG_UNSEQUENCED; + channel = SYSCH_UNRELIABLE; + } break; + case TRANSFER_MODE_UNRELIABLE_ORDERED: { + packet_flags = 0; + channel = SYSCH_UNRELIABLE; + } break; + case TRANSFER_MODE_RELIABLE: { + packet_flags = ENET_PACKET_FLAG_RELIABLE; + channel = SYSCH_RELIABLE; + } break; + } } ENetPacket *packet = enet_packet_create(nullptr, p_buffer_size + 8, packet_flags); diff --git a/modules/enet/enet_multiplayer_peer.h b/modules/enet/enet_multiplayer_peer.h index 703396d0cb7c..78e280db7c90 100644 --- a/modules/enet/enet_multiplayer_peer.h +++ b/modules/enet/enet_multiplayer_peer.h @@ -47,10 +47,10 @@ private: }; enum { - SYSCH_CONFIG, - SYSCH_RELIABLE, - SYSCH_UNRELIABLE, - SYSCH_MAX + SYSCH_CONFIG = 0, + SYSCH_RELIABLE = 1, + SYSCH_UNRELIABLE = 2, + SYSCH_MAX = 3 }; enum Mode { @@ -65,6 +65,7 @@ private: uint32_t unique_id = 0; int target_peer = 0; + int transfer_channel = 0; TransferMode transfer_mode = TRANSFER_MODE_RELIABLE; bool refuse_connections = false; @@ -100,6 +101,9 @@ protected: static void _bind_methods(); 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_target_peer(int p_peer) override; diff --git a/modules/gdnative/include/net/godot_net.h b/modules/gdnative/include/net/godot_net.h index 94e7739ef9a1..3fb7b9e1ccf7 100644 --- a/modules/gdnative/include/net/godot_net.h +++ b/modules/gdnative/include/net/godot_net.h @@ -91,6 +91,8 @@ typedef struct { godot_int (*get_max_packet_size)(const void *); /* This is MultiplayerPeer */ + void (*set_transfer_channel)(void *, godot_int); + godot_int (*get_transfer_channel)(void *); void (*set_transfer_mode)(void *, godot_int); godot_int (*get_transfer_mode)(const void *); // 0 = broadcast, 1 = server, <0 = all but abs(value) diff --git a/modules/gdnative/net/multiplayer_peer_gdnative.cpp b/modules/gdnative/net/multiplayer_peer_gdnative.cpp index 8ceba0f339a9..9908ed453362 100644 --- a/modules/gdnative/net/multiplayer_peer_gdnative.cpp +++ b/modules/gdnative/net/multiplayer_peer_gdnative.cpp @@ -62,6 +62,16 @@ int MultiplayerPeerGDNative::get_available_packet_count() const { } /* MultiplayerPeer */ +void MultiplayerPeerGDNative::set_transfer_channel(int p_channel) { + ERR_FAIL_COND(interface == nullptr); + return interface->set_transfer_channel(interface->data, p_channel); +} + +int MultiplayerPeerGDNative::get_transfer_channel() const { + ERR_FAIL_COND_V(interface == nullptr, 0); + return interface->get_transfer_channel(interface->data); +} + void MultiplayerPeerGDNative::set_transfer_mode(TransferMode p_mode) { ERR_FAIL_COND(interface == nullptr); interface->set_transfer_mode(interface->data, (godot_int)p_mode); @@ -113,6 +123,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("refuse_new_connections", true); } diff --git a/modules/gdnative/net/multiplayer_peer_gdnative.h b/modules/gdnative/net/multiplayer_peer_gdnative.h index 7c10ab77f743..ab084faae6d8 100644 --- a/modules/gdnative/net/multiplayer_peer_gdnative.h +++ b/modules/gdnative/net/multiplayer_peer_gdnative.h @@ -56,6 +56,8 @@ public: virtual int get_available_packet_count() const override; /* 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_target_peer(int p_peer_id) override; diff --git a/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml index 0c4a0d4ea090..c53af22ae18f 100644 --- a/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml +++ b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml @@ -51,10 +51,12 @@ + 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). diff --git a/modules/webrtc/webrtc_multiplayer_peer.cpp b/modules/webrtc/webrtc_multiplayer_peer.cpp index 9b08a26aede7..95c8c1344922 100644 --- a/modules/webrtc/webrtc_multiplayer_peer.cpp +++ b/modules/webrtc/webrtc_multiplayer_peer.cpp @@ -34,7 +34,7 @@ #include "core/os/os.h" void WebRTCMultiplayerPeer::_bind_methods() { - ClassDB::bind_method(D_METHOD("initialize", "peer_id", "server_compatibility"), &WebRTCMultiplayerPeer::initialize, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("initialize", "peer_id", "server_compatibility", "channels_config"), &WebRTCMultiplayerPeer::initialize, DEFVAL(false), DEFVAL(Array())); ClassDB::bind_method(D_METHOD("add_peer", "peer", "peer_id", "unreliable_lifetime"), &WebRTCMultiplayerPeer::add_peer, DEFVAL(1)); ClassDB::bind_method(D_METHOD("remove_peer", "peer_id"), &WebRTCMultiplayerPeer::remove_peer); ClassDB::bind_method(D_METHOD("has_peer", "peer_id"), &WebRTCMultiplayerPeer::has_peer); @@ -43,6 +43,14 @@ void WebRTCMultiplayerPeer::_bind_methods() { ClassDB::bind_method(D_METHOD("close"), &WebRTCMultiplayerPeer::close); } +void WebRTCMultiplayerPeer::set_transfer_channel(int p_channel) { + transfer_channel = p_channel; +} + +int WebRTCMultiplayerPeer::get_transfer_channel() const { + return transfer_channel; +} + void WebRTCMultiplayerPeer::set_transfer_mode(TransferMode p_mode) { transfer_mode = p_mode; } @@ -192,8 +200,34 @@ MultiplayerPeer::ConnectionStatus WebRTCMultiplayerPeer::get_connection_status() return connection_status; } -Error WebRTCMultiplayerPeer::initialize(int p_self_id, bool p_server_compat) { - ERR_FAIL_COND_V(p_self_id < 0 || p_self_id > ~(1 << 31), ERR_INVALID_PARAMETER); +Error WebRTCMultiplayerPeer::initialize(int p_self_id, bool p_server_compat, Array p_channels_config) { + 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'"); + int mode = p_channels_config[i].operator int(); + // Initialize data channel configurations. + Dictionary cfg; + cfg["id"] = CH_RESERVED_MAX + i + 1; + cfg["negotiated"] = true; + cfg["ordered"] = true; + + switch (mode) { + case TRANSFER_MODE_UNRELIABLE_ORDERED: + cfg["maxPacketLifetime"] = 1; + break; + case TRANSFER_MODE_UNRELIABLE: + cfg["maxPacketLifetime"] = 1; + cfg["ordered"] = false; + break; + case 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)); + } + channels_config.push_back(cfg); + } + unique_id = p_self_id; server_compat = p_server_compat; @@ -260,17 +294,23 @@ Error WebRTCMultiplayerPeer::add_peer(Ref p_peer, int p_pe cfg["id"] = 1; peer->channels[CH_RELIABLE] = p_peer->create_data_channel("reliable", cfg); - ERR_FAIL_COND_V(!peer->channels[CH_RELIABLE].is_valid(), FAILED); + ERR_FAIL_COND_V(peer->channels[CH_RELIABLE].is_null(), FAILED); cfg["id"] = 2; cfg["maxPacketLifetime"] = p_unreliable_lifetime; peer->channels[CH_ORDERED] = p_peer->create_data_channel("ordered", cfg); - ERR_FAIL_COND_V(!peer->channels[CH_ORDERED].is_valid(), FAILED); + ERR_FAIL_COND_V(peer->channels[CH_ORDERED].is_null(), FAILED); cfg["id"] = 3; cfg["ordered"] = false; peer->channels[CH_UNRELIABLE] = p_peer->create_data_channel("unreliable", cfg); - ERR_FAIL_COND_V(!peer->channels[CH_UNRELIABLE].is_valid(), FAILED); + ERR_FAIL_COND_V(peer->channels[CH_UNRELIABLE].is_null(), FAILED); + + for (const Dictionary &dict : channels_config) { + Ref ch = p_peer->create_data_channel(String::num_int64(dict["id"]), dict); + ERR_FAIL_COND_V(ch.is_null(), FAILED); + peer->channels.push_back(ch); + } peer_map[p_peer_id] = peer; // add the new peer connection to the peer_map @@ -312,17 +352,21 @@ Error WebRTCMultiplayerPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_ Error WebRTCMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) { ERR_FAIL_COND_V(connection_status == CONNECTION_DISCONNECTED, ERR_UNCONFIGURED); - int ch = CH_RELIABLE; - switch (transfer_mode) { - case TRANSFER_MODE_RELIABLE: - ch = CH_RELIABLE; - break; - case TRANSFER_MODE_UNRELIABLE_ORDERED: - ch = CH_ORDERED; - break; - case TRANSFER_MODE_UNRELIABLE: - ch = CH_UNRELIABLE; - break; + int ch = transfer_channel; + if (ch == 0) { + switch (transfer_mode) { + case TRANSFER_MODE_RELIABLE: + ch = CH_RELIABLE; + break; + case TRANSFER_MODE_UNRELIABLE_ORDERED: + ch = CH_ORDERED; + break; + case TRANSFER_MODE_UNRELIABLE: + ch = CH_UNRELIABLE; + break; + } + } else { + ch += CH_RESERVED_MAX - 1; } Map>::Element *E = nullptr; @@ -331,8 +375,8 @@ Error WebRTCMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_si E = peer_map.find(target_peer); ERR_FAIL_COND_V_MSG(!E, ERR_INVALID_PARAMETER, "Invalid target peer: " + itos(target_peer) + "."); - ERR_FAIL_COND_V(E->value()->channels.size() <= ch, ERR_BUG); - ERR_FAIL_COND_V(!E->value()->channels[ch].is_valid(), ERR_BUG); + ERR_FAIL_COND_V_MSG(E->value()->channels.size() <= ch, ERR_INVALID_PARAMETER, vformat("Unable to send packet on channel %d, max channels: %d", ch, E->value()->channels.size())); + ERR_FAIL_COND_V(E->value()->channels[ch].is_null(), ERR_BUG); return E->value()->channels[ch]->put_packet(p_buffer, p_buffer_size); } else { @@ -344,7 +388,8 @@ Error WebRTCMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_si continue; } - ERR_CONTINUE(F->value()->channels.size() <= ch || !F->value()->channels[ch].is_valid()); + ERR_CONTINUE_MSG(F->value()->channels.size() <= ch, vformat("Unable to send packet on channel %d, max channels: %d", ch, E->value()->channels.size())); + ERR_CONTINUE(F->value()->channels[ch].is_null()); F->value()->channels[ch]->put_packet(p_buffer, p_buffer_size); } } @@ -370,23 +415,13 @@ int WebRTCMultiplayerPeer::get_max_packet_size() const { void WebRTCMultiplayerPeer::close() { peer_map.clear(); + channels_config.clear(); unique_id = 0; next_packet_peer = 0; target_peer = 0; connection_status = CONNECTION_DISCONNECTED; } -WebRTCMultiplayerPeer::WebRTCMultiplayerPeer() { - unique_id = 0; - next_packet_peer = 0; - target_peer = 0; - client_count = 0; - transfer_mode = TRANSFER_MODE_RELIABLE; - refuse_connections = false; - connection_status = CONNECTION_DISCONNECTED; - server_compat = false; -} - WebRTCMultiplayerPeer::~WebRTCMultiplayerPeer() { close(); } diff --git a/modules/webrtc/webrtc_multiplayer_peer.h b/modules/webrtc/webrtc_multiplayer_peer.h index 1d9387b6dc0a..ef4fe1678c2a 100644 --- a/modules/webrtc/webrtc_multiplayer_peer.h +++ b/modules/webrtc/webrtc_multiplayer_peer.h @@ -62,25 +62,27 @@ private: } }; - uint32_t unique_id; - int target_peer; - int client_count; - bool refuse_connections; - ConnectionStatus connection_status; - TransferMode transfer_mode; - int next_packet_peer; - bool server_compat; + uint32_t unique_id = 0; + int target_peer = 0; + int client_count = 0; + bool refuse_connections = false; + ConnectionStatus connection_status = CONNECTION_DISCONNECTED; + int transfer_channel = 0; + TransferMode transfer_mode = TRANSFER_MODE_RELIABLE; + int next_packet_peer = 0; + bool server_compat = false; Map> peer_map; + List channels_config; void _peer_to_dict(Ref p_connected_peer, Dictionary &r_dict); void _find_next_peer(); public: - WebRTCMultiplayerPeer(); + WebRTCMultiplayerPeer() {} ~WebRTCMultiplayerPeer(); - Error initialize(int p_self_id, bool p_server_compat = false); + Error initialize(int p_self_id, bool p_server_compat = false, Array p_channels_config = Array()); Error add_peer(Ref p_peer, int p_peer_id, int p_unreliable_lifetime = 1); void remove_peer(int p_peer_id); bool has_peer(int p_peer_id); @@ -95,6 +97,8 @@ public: int get_max_packet_size() const override; // 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_target_peer(int p_peer_id) override; diff --git a/modules/websocket/websocket_multiplayer_peer.cpp b/modules/websocket/websocket_multiplayer_peer.cpp index 52d9a602a19e..163cc7706bbc 100644 --- a/modules/websocket/websocket_multiplayer_peer.cpp +++ b/modules/websocket/websocket_multiplayer_peer.cpp @@ -105,6 +105,14 @@ Error WebSocketMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer // // MultiplayerPeer // +void WebSocketMultiplayerPeer::set_transfer_channel(int p_channel) { + // Websocket does not have channels. +} + +int WebSocketMultiplayerPeer::get_transfer_channel() const { + return 0; +} + void WebSocketMultiplayerPeer::set_transfer_mode(TransferMode p_mode) { // Websocket uses TCP, reliable } diff --git a/modules/websocket/websocket_multiplayer_peer.h b/modules/websocket/websocket_multiplayer_peer.h index 4e80f876d63f..0fee196f41fc 100644 --- a/modules/websocket/websocket_multiplayer_peer.h +++ b/modules/websocket/websocket_multiplayer_peer.h @@ -78,6 +78,8 @@ protected: 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_target_peer(int p_target_peer) override;