summaryrefslogtreecommitdiff
path: root/modules/webrtc
diff options
context:
space:
mode:
authorFabio Alessandrelli <fabio.alessandrelli@gmail.com>2022-10-08 20:50:19 +0200
committerFabio Alessandrelli <fabio.alessandrelli@gmail.com>2022-10-27 18:08:58 +0200
commit7536d15fe3c5991b79aa54f0db3cf110e882e87a (patch)
tree4552f62d1fa5054828e47132cd785322abcea0cf /modules/webrtc
parent03e5de37ae3228de26e7b83888c542a9f400b5d9 (diff)
[MP] Let MultiplayerAPI handle packet relaying and peer signaling.
MultiplayerPeer changes: - Adds is_server_relay_supported virtual method Informs the upper MultiplayerAPI layer if it can signal peers connected to the server to other clients, and perform packet relaying among them. - Adds get_packet_channel and get_packet_mode virtual methods Allows the MultiplayerAPI to retrieve the channel and transfer modes to use when relaying the last received packet. SceneMultiplayerPeer changes: - Implement peer signaling and packet relaying when the MultiplayerPeer advertise they are supported. ENet, WebRTC, WebSocket changes: - Removed custom code for relaying from WebSocket and ENet, and let it be handled by the upper layer. - Update WebRTC to split create_client, create_server, and create_mesh, with the latter behaving like the old initialize with "server_compatibility = false", and the first two supporting the upper layer relaying protocol.
Diffstat (limited to 'modules/webrtc')
-rw-r--r--modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml39
-rw-r--r--modules/webrtc/webrtc_multiplayer_peer.cpp85
-rw-r--r--modules/webrtc/webrtc_multiplayer_peer.h20
3 files changed, 106 insertions, 38 deletions
diff --git a/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml
index 927888fe21..0b42c6ed35 100644
--- a/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml
+++ b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml
@@ -6,7 +6,7 @@
<description>
This class constructs a full mesh of [WebRTCPeerConnection] (one connection for each peer) that can be used as a [member MultiplayerAPI.multiplayer_peer].
You can add each [WebRTCPeerConnection] via [method add_peer] or remove them via [method remove_peer]. Peers must be added in [constant WebRTCPeerConnection.STATE_NEW] state to allow it to create the appropriate channels. This class will not create offers nor set descriptions, it will only poll them, and notify connections and disconnections.
- [signal MultiplayerPeer.connection_succeeded] and [signal MultiplayerPeer.server_disconnected] will not be emitted unless [code]server_compatibility[/code] is [code]true[/code] in [method initialize]. Beside that data transfer works like in a [MultiplayerPeer].
+ [signal MultiplayerPeer.connection_succeeded] and [signal MultiplayerPeer.server_disconnected] will not be emitted unless the peer is created using [method create_client]. Beside that data transfer works like in a [MultiplayerPeer].
[b]Note:[/b] When exporting to Android, make sure to enable the [code]INTERNET[/code] permission in the Android export preset before exporting the project or using one-click deploy. Otherwise, network communication of any kind will be blocked by Android.
</description>
<tutorials>
@@ -28,6 +28,31 @@
Close all the add peer connections and channels, freeing all resources.
</description>
</method>
+ <method name="create_client">
+ <return type="int" enum="Error" />
+ <param index="0" name="peer_id" type="int" />
+ <param index="1" name="channels_config" type="Array" default="[]" />
+ <description>
+ Initialize the multiplayer peer as a client with the given [code]peer_id[/code] (must be between 2 and 2147483647). In this mode, you should only call [method add_peer] once and with [code]peer_id[/code] of [code]1[/code]. This mode enables [method MultiplayerPeer.is_server_relay_supported], allowing the upper [MultiplayerAPI] layer to perform peer exchange and packet relaying.
+ 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="create_mesh">
+ <return type="int" enum="Error" />
+ <param index="0" name="peer_id" type="int" />
+ <param index="1" name="channels_config" type="Array" default="[]" />
+ <description>
+ Initialize the multiplayer peer as a mesh (i.e. all peers connect to each other) with the given [code]peer_id[/code] (must be between 1 and 2147483647).
+ </description>
+ </method>
+ <method name="create_server">
+ <return type="int" enum="Error" />
+ <param index="0" name="channels_config" type="Array" default="[]" />
+ <description>
+ Initialize the multiplayer peer as a server (with unique ID of [code]1[/code]). This mode enables [method MultiplayerPeer.is_server_relay_supported], allowing the upper [MultiplayerAPI] layer to perform peer exchange and packet relaying.
+ 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="get_peer">
<return type="Dictionary" />
<param index="0" name="peer_id" type="int" />
@@ -48,18 +73,6 @@
Returns [code]true[/code] if the given [code]peer_id[/code] is in the peers map (it might not be connected though).
</description>
</method>
- <method name="initialize">
- <return type="int" enum="Error" />
- <param index="0" name="peer_id" type="int" />
- <param index="1" name="server_compatibility" type="bool" default="false" />
- <param 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">
<return type="void" />
<param index="0" name="peer_id" type="int" />
diff --git a/modules/webrtc/webrtc_multiplayer_peer.cpp b/modules/webrtc/webrtc_multiplayer_peer.cpp
index e03b6b2473..5ea81d5a1b 100644
--- a/modules/webrtc/webrtc_multiplayer_peer.cpp
+++ b/modules/webrtc/webrtc_multiplayer_peer.cpp
@@ -34,7 +34,9 @@
#include "core/os/os.h"
void WebRTCMultiplayerPeer::_bind_methods() {
- ClassDB::bind_method(D_METHOD("initialize", "peer_id", "server_compatibility", "channels_config"), &WebRTCMultiplayerPeer::initialize, DEFVAL(false), DEFVAL(Array()));
+ ClassDB::bind_method(D_METHOD("create_server", "channels_config"), &WebRTCMultiplayerPeer::create_server, DEFVAL(Array()));
+ ClassDB::bind_method(D_METHOD("create_client", "peer_id", "channels_config"), &WebRTCMultiplayerPeer::create_client, DEFVAL(Array()));
+ ClassDB::bind_method(D_METHOD("create_mesh", "peer_id", "channels_config"), &WebRTCMultiplayerPeer::create_mesh, 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);
@@ -52,6 +54,15 @@ int WebRTCMultiplayerPeer::get_packet_peer() const {
return next_packet_peer;
}
+int WebRTCMultiplayerPeer::get_packet_channel() const {
+ return next_packet_channel < CH_RESERVED_MAX ? 0 : next_packet_channel - CH_RESERVED_MAX + 1;
+}
+
+MultiplayerPeer::TransferMode WebRTCMultiplayerPeer::get_packet_mode() const {
+ ERR_FAIL_INDEX_V(next_packet_channel, channels_modes.size(), TRANSFER_MODE_RELIABLE);
+ return channels_modes[next_packet_channel];
+}
+
bool WebRTCMultiplayerPeer::is_server() const {
return unique_id == TARGET_PEER_SERVER;
}
@@ -113,24 +124,14 @@ void WebRTCMultiplayerPeer::poll() {
// Signal newly connected peers
for (int &E : add) {
// Already connected to server: simply notify new peer.
- // NOTE: Mesh is always connected.
- if (connection_status == CONNECTION_CONNECTED) {
- emit_signal(SNAME("peer_connected"), E);
- }
-
- // Server emulation mode suppresses peer_conencted until server connects.
- if (server_compat && E == TARGET_PEER_SERVER) {
+ if (network_mode == MODE_CLIENT) {
+ ERR_CONTINUE(E != TARGET_PEER_SERVER); // Bug.
// Server connected.
connection_status = CONNECTION_CONNECTED;
emit_signal(SNAME("peer_connected"), TARGET_PEER_SERVER);
emit_signal(SNAME("connection_succeeded"));
- // Notify of all previously connected peers
- for (const KeyValue<int, Ref<ConnectedPeer>> &F : peer_map) {
- if (F.key != 1 && F.value->connected) {
- emit_signal(SNAME("peer_connected"), F.key);
- }
- }
- break; // Because we already notified of all newly added peers.
+ } else {
+ emit_signal(SNAME("peer_connected"), E);
}
}
// Fetch next packet
@@ -150,11 +151,14 @@ void WebRTCMultiplayerPeer::_find_next_peer() {
++E;
continue;
}
+ int idx = 0;
for (const Ref<WebRTCDataChannel> &F : E->value->channels) {
if (F->get_available_packet_count()) {
+ next_packet_channel = idx;
next_packet_peer = E->key;
return;
}
+ idx++;
}
++E;
}
@@ -165,11 +169,14 @@ void WebRTCMultiplayerPeer::_find_next_peer() {
++E;
continue;
}
+ int idx = 0;
for (const Ref<WebRTCDataChannel> &F : E->value->channels) {
if (F->get_available_packet_count()) {
+ next_packet_channel = idx;
next_packet_peer = E->key;
return;
}
+ idx++;
}
if (E->key == (int)next_packet_peer) {
break;
@@ -177,6 +184,7 @@ void WebRTCMultiplayerPeer::_find_next_peer() {
++E;
}
// No packet found
+ next_packet_channel = 0;
next_packet_peer = 0;
}
@@ -184,11 +192,28 @@ MultiplayerPeer::ConnectionStatus WebRTCMultiplayerPeer::get_connection_status()
return connection_status;
}
-Error WebRTCMultiplayerPeer::initialize(int p_self_id, bool p_server_compat, Array p_channels_config) {
+Error WebRTCMultiplayerPeer::create_server(Array p_channels_config) {
+ return _initialize(1, MODE_SERVER, p_channels_config);
+}
+
+Error WebRTCMultiplayerPeer::create_client(int p_self_id, Array p_channels_config) {
+ ERR_FAIL_COND_V_MSG(p_self_id == 1, ERR_INVALID_PARAMETER, "Clients cannot have ID 1.");
+ return _initialize(p_self_id, MODE_CLIENT, p_channels_config);
+}
+
+Error WebRTCMultiplayerPeer::create_mesh(int p_self_id, Array p_channels_config) {
+ return _initialize(p_self_id, MODE_MESH, p_channels_config);
+}
+
+Error WebRTCMultiplayerPeer::_initialize(int p_self_id, NetworkMode p_mode, Array p_channels_config) {
ERR_FAIL_COND_V(p_self_id < 1 || p_self_id > ~(1 << 31), ERR_INVALID_PARAMETER);
channels_config.clear();
+ channels_modes.clear();
+ channels_modes.push_back(TRANSFER_MODE_RELIABLE);
+ channels_modes.push_back(TRANSFER_MODE_UNRELIABLE_ORDERED);
+ channels_modes.push_back(TRANSFER_MODE_UNRELIABLE);
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.Multiplayer::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.TransferMode'");
int mode = p_channels_config[i].operator int();
// Initialize data channel configurations.
Dictionary cfg;
@@ -207,16 +232,17 @@ Error WebRTCMultiplayerPeer::initialize(int p_self_id, bool p_server_compat, Arr
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.Multiplayer::TransferMode'. Got: %d", mode));
+ 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);
+ channels_modes.push_back((TransferMode)mode);
}
unique_id = p_self_id;
- server_compat = p_server_compat;
+ network_mode = p_mode;
// Mesh and server are always connected
- if (!server_compat || p_self_id == 1) {
+ if (p_mode != MODE_CLIENT) {
connection_status = CONNECTION_CONNECTED;
} else {
connection_status = CONNECTION_CONNECTING;
@@ -224,6 +250,10 @@ Error WebRTCMultiplayerPeer::initialize(int p_self_id, bool p_server_compat, Arr
return OK;
}
+bool WebRTCMultiplayerPeer::is_server_relay_supported() const {
+ return network_mode == MODE_SERVER || network_mode == MODE_CLIENT;
+}
+
int WebRTCMultiplayerPeer::get_unique_id() const {
ERR_FAIL_COND_V(connection_status == CONNECTION_DISCONNECTED, 1);
return unique_id;
@@ -261,7 +291,10 @@ Dictionary WebRTCMultiplayerPeer::get_peers() {
}
Error WebRTCMultiplayerPeer::add_peer(Ref<WebRTCPeerConnection> p_peer, int p_peer_id, int p_unreliable_lifetime) {
- ERR_FAIL_COND_V(p_peer_id < 0 || p_peer_id > ~(1 << 31), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(network_mode == MODE_NONE, ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(network_mode == MODE_CLIENT && p_peer_id != 1, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(network_mode == MODE_SERVER && p_peer_id == 1, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(p_peer_id < 1 || p_peer_id > ~(1 << 31), ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(p_unreliable_lifetime < 0, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(is_refusing_new_connections(), ERR_UNAUTHORIZED);
// Peer must be valid, and in new state (to create data channels)
@@ -308,8 +341,12 @@ void WebRTCMultiplayerPeer::remove_peer(int p_peer_id) {
if (peer->connected) {
peer->connected = false;
emit_signal(SNAME("peer_disconnected"), p_peer_id);
- if (server_compat && p_peer_id == TARGET_PEER_SERVER) {
- emit_signal(SNAME("server_disconnected"));
+ if (network_mode == MODE_CLIENT && p_peer_id == TARGET_PEER_SERVER) {
+ if (connection_status == CONNECTION_CONNECTING) {
+ emit_signal(SNAME("connection_failed"));
+ } else {
+ emit_signal(SNAME("server_disconnected"));
+ }
connection_status = CONNECTION_DISCONNECTED;
}
}
@@ -403,7 +440,9 @@ void WebRTCMultiplayerPeer::close() {
channels_config.clear();
unique_id = 0;
next_packet_peer = 0;
+ next_packet_channel = 0;
target_peer = 0;
+ network_mode = MODE_NONE;
connection_status = CONNECTION_DISCONNECTED;
}
diff --git a/modules/webrtc/webrtc_multiplayer_peer.h b/modules/webrtc/webrtc_multiplayer_peer.h
index ea7c60036b..3f608200fd 100644
--- a/modules/webrtc/webrtc_multiplayer_peer.h
+++ b/modules/webrtc/webrtc_multiplayer_peer.h
@@ -48,6 +48,13 @@ private:
CH_RESERVED_MAX = 3
};
+ enum NetworkMode {
+ MODE_NONE,
+ MODE_SERVER,
+ MODE_CLIENT,
+ MODE_MESH,
+ };
+
class ConnectedPeer : public RefCounted {
public:
Ref<WebRTCPeerConnection> connection;
@@ -67,19 +74,25 @@ private:
int client_count = 0;
ConnectionStatus connection_status = CONNECTION_DISCONNECTED;
int next_packet_peer = 0;
- bool server_compat = false;
+ int next_packet_channel = 0;
+ NetworkMode network_mode = MODE_NONE;
HashMap<int, Ref<ConnectedPeer>> peer_map;
+ List<TransferMode> channels_modes;
List<Dictionary> channels_config;
void _peer_to_dict(Ref<ConnectedPeer> p_connected_peer, Dictionary &r_dict);
void _find_next_peer();
+ Ref<ConnectedPeer> _get_next_peer();
+ Error _initialize(int p_self_id, NetworkMode p_mode, Array p_channels_config = Array());
public:
WebRTCMultiplayerPeer() {}
~WebRTCMultiplayerPeer();
- Error initialize(int p_self_id, bool p_server_compat = false, Array p_channels_config = Array());
+ Error create_server(Array p_channels_config = Array());
+ Error create_client(int p_self_id, Array p_channels_config = Array());
+ Error create_mesh(int p_self_id, 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);
@@ -98,8 +111,11 @@ public:
int get_unique_id() const override;
int get_packet_peer() const override;
+ int get_packet_channel() const override;
+ TransferMode get_packet_mode() const override;
bool is_server() const override;
+ bool is_server_relay_supported() const override;
void poll() override;