You've already forked godot
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:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user