1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-18 14:21:41 +00:00

[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.
This commit is contained in:
Fabio Alessandrelli
2022-10-08 20:50:19 +02:00
parent 03e5de37ae
commit 7536d15fe3
17 changed files with 465 additions and 446 deletions

View File

@@ -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;
}