summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabio Alessandrelli <fabio.alessandrelli@gmail.com>2021-07-27 12:06:48 +0200
committerFabio Alessandrelli <fabio.alessandrelli@gmail.com>2021-07-30 17:29:50 +0200
commit2cf39b97ae326a28015b67221b928e4861380d29 (patch)
tree12d05483c198a7387768a6739fedbf143bd1ae0d
parentc27ef1565ff44eaacc081081b6b21b23665fbe10 (diff)
[Net] Implement RPC channels in MultiplayerAPI.
-rw-r--r--core/io/multiplayer_api.cpp8
-rw-r--r--core/io/multiplayer_api.h2
-rw-r--r--core/io/multiplayer_peer.cpp3
-rw-r--r--core/io/multiplayer_peer.h2
-rw-r--r--doc/classes/MultiplayerAPI.xml1
-rw-r--r--doc/classes/MultiplayerPeer.xml4
-rw-r--r--modules/enet/enet_multiplayer_peer.cpp39
-rw-r--r--modules/enet/enet_multiplayer_peer.h12
-rw-r--r--modules/gdnative/include/net/godot_net.h2
-rw-r--r--modules/gdnative/net/multiplayer_peer_gdnative.cpp11
-rw-r--r--modules/gdnative/net/multiplayer_peer_gdnative.h2
-rw-r--r--modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml2
-rw-r--r--modules/webrtc/webrtc_multiplayer_peer.cpp97
-rw-r--r--modules/webrtc/webrtc_multiplayer_peer.h24
-rw-r--r--modules/websocket/websocket_multiplayer_peer.cpp8
-rw-r--r--modules/websocket/websocket_multiplayer_peer.h2
16 files changed, 157 insertions, 62 deletions
diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp
index d4f09b2135..1c3f231170 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<uint8_t> p_data, int p_to, MultiplayerPeer::TransferMode p_mode) {
+Error MultiplayerAPI::send_bytes(Vector<uint8_t> 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<uint8_t> 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 cc994a9852..011bc3dde9 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<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);
+ 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);
// 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 8b3b1eef8e..83cf24d7e3 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 91a3ad7954..7ca4e7930b 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 104f649921..552e0fce4c 100644
--- a/doc/classes/MultiplayerAPI.xml
+++ b/doc/classes/MultiplayerAPI.xml
@@ -61,6 +61,7 @@
<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="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.
</description>
diff --git a/doc/classes/MultiplayerPeer.xml b/doc/classes/MultiplayerPeer.xml
index 88cd058c51..adaa359168 100644
--- a/doc/classes/MultiplayerPeer.xml
+++ b/doc/classes/MultiplayerPeer.xml
@@ -55,6 +55,10 @@
<member name="refuse_new_connections" type="bool" setter="set_refuse_new_connections" getter="is_refusing_new_connections" default="true">
If [code]true[/code], this [MultiplayerPeer] refuses new connections.
</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.
+ </member>
<member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" enum="MultiplayerPeer.TransferMode" default="0">
The manner in which to send packets to the [code]target_peer[/code]. See [enum TransferMode].
</member>
diff --git a/modules/enet/enet_multiplayer_peer.cpp b/modules/enet/enet_multiplayer_peer.cpp
index 28b6bb035a..aa0e09bcde 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 703396d0cb..78e280db7c 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 94e7739ef9..3fb7b9e1cc 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 8ceba0f339..9908ed4533 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 7c10ab77f7..ab084faae6 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 0c4a0d4ea0..c53af22ae1 100644
--- a/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml
+++ b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml
@@ -51,10 +51,12 @@
<return type="int" enum="Error" />
<argument index="0" name="peer_id" type="int" />
<argument index="1" name="server_compatibility" type="bool" default="false" />
+ <argument index="2" name="channels_config" type="Array" default="[]" />
<description>
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).
</description>
</method>
<method name="remove_peer">
diff --git a/modules/webrtc/webrtc_multiplayer_peer.cpp b/modules/webrtc/webrtc_multiplayer_peer.cpp
index 9b08a26aed..95c8c13449 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<WebRTCPeerConnection> 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<WebRTCDataChannel> 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<int, Ref<ConnectedPeer>>::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 1d9387b6dc..ef4fe1678c 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<int, Ref<ConnectedPeer>> peer_map;
+ List<Dictionary> channels_config;
void _peer_to_dict(Ref<ConnectedPeer> 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<WebRTCPeerConnection> 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 52d9a602a1..163cc7706b 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 4e80f876d6..0fee196f41 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;