2019-05-11 01:53:49 +02:00
/**************************************************************************/
2021-07-12 16:26:37 +02:00
/* webrtc_multiplayer_peer.cpp */
2019-05-11 01:53:49 +02:00
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
2021-07-12 16:26:37 +02:00
# include "webrtc_multiplayer_peer.h"
2019-05-11 01:53:49 +02:00
# include "core/io/marshalls.h"
# include "core/os/os.h"
2021-07-12 16:26:37 +02:00
void WebRTCMultiplayerPeer : : _bind_methods ( ) {
2022-10-08 20:50:19 +02:00
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 ( ) ) ) ;
2021-07-12 16:26:37 +02:00
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 ) ;
ClassDB : : bind_method ( D_METHOD ( " get_peer " , " peer_id " ) , & WebRTCMultiplayerPeer : : get_peer ) ;
ClassDB : : bind_method ( D_METHOD ( " get_peers " ) , & WebRTCMultiplayerPeer : : get_peers ) ;
2019-05-11 01:53:49 +02:00
}
2021-07-12 16:26:37 +02:00
void WebRTCMultiplayerPeer : : set_target_peer ( int p_peer_id ) {
2019-05-11 01:53:49 +02:00
target_peer = p_peer_id ;
}
2021-07-12 16:11:05 +02:00
/* Returns the ID of the MultiplayerPeer who sent the most recent packet: */
2021-07-12 16:26:37 +02:00
int WebRTCMultiplayerPeer : : get_packet_peer ( ) const {
2019-05-11 01:53:49 +02:00
return next_packet_peer ;
}
2022-10-08 20:50:19 +02:00
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 ) ;
2024-04-15 15:18:34 +02:00
return channels_modes . get ( next_packet_channel ) ;
2022-10-08 20:50:19 +02:00
}
2021-07-12 16:26:37 +02:00
bool WebRTCMultiplayerPeer : : is_server ( ) const {
2019-05-11 01:53:49 +02:00
return unique_id = = TARGET_PEER_SERVER ;
}
2021-07-12 16:26:37 +02:00
void WebRTCMultiplayerPeer : : poll ( ) {
2020-05-14 16:41:43 +02:00
if ( peer_map . size ( ) = = 0 ) {
2019-05-11 01:53:49 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2019-05-11 01:53:49 +02:00
List < int > remove ;
List < int > add ;
2021-08-09 22:13:42 +02:00
for ( KeyValue < int , Ref < ConnectedPeer > > & E : peer_map ) {
Ref < ConnectedPeer > peer = E . value ;
2019-05-11 01:53:49 +02:00
peer - > connection - > poll ( ) ;
// Check peer state
switch ( peer - > connection - > get_connection_state ( ) ) {
case WebRTCPeerConnection : : STATE_NEW :
case WebRTCPeerConnection : : STATE_CONNECTING :
// Go to next peer, not ready yet.
continue ;
case WebRTCPeerConnection : : STATE_CONNECTED :
// Good to go, go ahead and check channel state.
break ;
default :
// Peer is closed or in error state. Got to next peer.
2021-08-09 22:13:42 +02:00
remove . push_back ( E . key ) ;
2019-05-11 01:53:49 +02:00
continue ;
}
// Check channels state
int ready = 0 ;
2020-03-17 07:33:00 +01:00
for ( List < Ref < WebRTCDataChannel > > : : Element * C = peer - > channels . front ( ) ; C & & C - > get ( ) . is_valid ( ) ; C = C - > next ( ) ) {
2019-05-11 01:53:49 +02:00
Ref < WebRTCDataChannel > ch = C - > get ( ) ;
switch ( ch - > get_ready_state ( ) ) {
case WebRTCDataChannel : : STATE_CONNECTING :
continue ;
case WebRTCDataChannel : : STATE_OPEN :
ready + + ;
continue ;
default :
// Channel was closed or in error state, remove peer id.
2021-08-09 22:13:42 +02:00
remove . push_back ( E . key ) ;
2019-05-11 01:53:49 +02:00
}
// We got a closed channel break out, the peer will be removed.
break ;
}
// This peer has newly connected, and all channels are now open.
if ( ready = = peer - > channels . size ( ) & & ! peer - > connected ) {
peer - > connected = true ;
2021-08-09 22:13:42 +02:00
add . push_back ( E . key ) ;
2019-05-11 01:53:49 +02:00
}
}
// Remove disconnected peers
2021-07-16 05:45:57 +02:00
for ( int & E : remove ) {
remove_peer ( E ) ;
if ( next_packet_peer = = E ) {
2019-05-11 01:53:49 +02:00
next_packet_peer = 0 ;
2020-05-14 16:41:43 +02:00
}
2019-05-11 01:53:49 +02:00
}
// Signal newly connected peers
2021-07-16 05:45:57 +02:00
for ( int & E : add ) {
2019-05-11 01:53:49 +02:00
// Already connected to server: simply notify new peer.
2022-10-08 20:50:19 +02:00
if ( network_mode = = MODE_CLIENT ) {
ERR_CONTINUE ( E ! = TARGET_PEER_SERVER ) ; // Bug.
2019-05-11 01:53:49 +02:00
// Server connected.
connection_status = CONNECTION_CONNECTED ;
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " peer_connected " ) , TARGET_PEER_SERVER ) ;
2022-10-08 20:50:19 +02:00
} else {
emit_signal ( SNAME ( " peer_connected " ) , E ) ;
2019-05-11 01:53:49 +02:00
}
}
// Fetch next packet
2020-05-14 16:41:43 +02:00
if ( next_packet_peer = = 0 ) {
2019-05-11 01:53:49 +02:00
_find_next_peer ( ) ;
2020-05-14 16:41:43 +02:00
}
2019-05-11 01:53:49 +02:00
}
2021-07-12 16:26:37 +02:00
void WebRTCMultiplayerPeer : : _find_next_peer ( ) {
2022-05-13 15:04:37 +02:00
HashMap < int , Ref < ConnectedPeer > > : : Iterator E = peer_map . find ( next_packet_peer ) ;
2020-05-14 16:41:43 +02:00
if ( E ) {
2022-05-13 15:04:37 +02:00
+ + E ;
2020-05-14 16:41:43 +02:00
}
2019-05-11 01:53:49 +02:00
// After last.
while ( E ) {
2022-05-13 15:04:37 +02:00
if ( ! E - > value - > connected ) {
+ + E ;
2021-12-15 10:58:48 +01:00
continue ;
}
2022-10-08 20:50:19 +02:00
int idx = 0 ;
2022-05-13 15:04:37 +02:00
for ( const Ref < WebRTCDataChannel > & F : E - > value - > channels ) {
2021-07-16 05:45:57 +02:00
if ( F - > get_available_packet_count ( ) ) {
2022-10-08 20:50:19 +02:00
next_packet_channel = idx ;
2022-05-13 15:04:37 +02:00
next_packet_peer = E - > key ;
2019-05-11 01:53:49 +02:00
return ;
}
2022-10-08 20:50:19 +02:00
idx + + ;
2019-05-11 01:53:49 +02:00
}
2022-05-13 15:04:37 +02:00
+ + E ;
2019-05-11 01:53:49 +02:00
}
2022-05-13 15:04:37 +02:00
E = peer_map . begin ( ) ;
2019-05-11 01:53:49 +02:00
// Before last
while ( E ) {
2022-05-13 15:04:37 +02:00
if ( ! E - > value - > connected ) {
+ + E ;
2021-12-15 10:58:48 +01:00
continue ;
}
2022-10-08 20:50:19 +02:00
int idx = 0 ;
2022-05-13 15:04:37 +02:00
for ( const Ref < WebRTCDataChannel > & F : E - > value - > channels ) {
2021-07-16 05:45:57 +02:00
if ( F - > get_available_packet_count ( ) ) {
2022-10-08 20:50:19 +02:00
next_packet_channel = idx ;
2022-05-13 15:04:37 +02:00
next_packet_peer = E - > key ;
2019-05-11 01:53:49 +02:00
return ;
}
2022-10-08 20:50:19 +02:00
idx + + ;
2019-05-11 01:53:49 +02:00
}
2022-05-13 15:04:37 +02:00
if ( E - > key = = ( int ) next_packet_peer ) {
2019-05-11 01:53:49 +02:00
break ;
2020-05-14 16:41:43 +02:00
}
2022-05-13 15:04:37 +02:00
+ + E ;
2019-05-11 01:53:49 +02:00
}
// No packet found
2022-10-08 20:50:19 +02:00
next_packet_channel = 0 ;
2019-05-11 01:53:49 +02:00
next_packet_peer = 0 ;
}
2021-07-12 16:26:37 +02:00
MultiplayerPeer : : ConnectionStatus WebRTCMultiplayerPeer : : get_connection_status ( ) const {
2019-05-11 01:53:49 +02:00
return connection_status ;
}
2022-10-08 20:50:19 +02:00
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 ) {
2021-07-27 12:06:48 +02:00
ERR_FAIL_COND_V ( p_self_id < 1 | | p_self_id > ~ ( 1 < < 31 ) , ERR_INVALID_PARAMETER ) ;
channels_config . clear ( ) ;
2022-10-08 20:50:19 +02:00
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 ) ;
2021-07-27 12:06:48 +02:00
for ( int i = 0 ; i < p_channels_config . size ( ) ; i + + ) {
2022-10-08 20:50:19 +02:00
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' " ) ;
2021-07-27 12:06:48 +02:00
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 ) {
2022-07-12 23:12:42 +02:00
case TRANSFER_MODE_UNRELIABLE_ORDERED :
2021-07-27 12:06:48 +02:00
cfg [ " maxPacketLifetime " ] = 1 ;
break ;
2022-07-12 23:12:42 +02:00
case TRANSFER_MODE_UNRELIABLE :
2021-07-27 12:06:48 +02:00
cfg [ " maxPacketLifetime " ] = 1 ;
cfg [ " ordered " ] = false ;
break ;
2022-07-12 23:12:42 +02:00
case TRANSFER_MODE_RELIABLE :
2021-07-27 12:06:48 +02:00
break ;
default :
2022-10-08 20:50:19 +02:00
ERR_FAIL_V_MSG ( ERR_INVALID_PARAMETER , vformat ( " The 'channels_config' array must contain only enum values from 'MultiplayerPeer.TransferMode'. Got: %d " , mode ) ) ;
2021-07-27 12:06:48 +02:00
}
channels_config . push_back ( cfg ) ;
2022-10-08 20:50:19 +02:00
channels_modes . push_back ( ( TransferMode ) mode ) ;
2021-07-27 12:06:48 +02:00
}
2019-05-11 01:53:49 +02:00
unique_id = p_self_id ;
2022-10-08 20:50:19 +02:00
network_mode = p_mode ;
2019-05-11 01:53:49 +02:00
// Mesh and server are always connected
2022-10-08 20:50:19 +02:00
if ( p_mode ! = MODE_CLIENT ) {
2019-05-11 01:53:49 +02:00
connection_status = CONNECTION_CONNECTED ;
2020-05-14 16:41:43 +02:00
} else {
2019-05-11 01:53:49 +02:00
connection_status = CONNECTION_CONNECTING ;
2020-05-14 16:41:43 +02:00
}
2019-05-11 01:53:49 +02:00
return OK ;
}
2022-10-08 20:50:19 +02:00
bool WebRTCMultiplayerPeer : : is_server_relay_supported ( ) const {
return network_mode = = MODE_SERVER | | network_mode = = MODE_CLIENT ;
}
2021-07-12 16:26:37 +02:00
int WebRTCMultiplayerPeer : : get_unique_id ( ) const {
2019-05-11 01:53:49 +02:00
ERR_FAIL_COND_V ( connection_status = = CONNECTION_DISCONNECTED , 1 ) ;
return unique_id ;
}
2021-07-12 16:26:37 +02:00
void WebRTCMultiplayerPeer : : _peer_to_dict ( Ref < ConnectedPeer > p_connected_peer , Dictionary & r_dict ) {
2019-05-11 01:53:49 +02:00
Array channels ;
2021-07-26 17:50:35 +02:00
for ( Ref < WebRTCDataChannel > & F : p_connected_peer - > channels ) {
2021-07-16 05:45:57 +02:00
channels . push_back ( F ) ;
2019-05-11 01:53:49 +02:00
}
r_dict [ " connection " ] = p_connected_peer - > connection ;
r_dict [ " connected " ] = p_connected_peer - > connected ;
r_dict [ " channels " ] = channels ;
}
2021-07-12 16:26:37 +02:00
bool WebRTCMultiplayerPeer : : has_peer ( int p_peer_id ) {
2019-05-11 01:53:49 +02:00
return peer_map . has ( p_peer_id ) ;
}
2021-07-12 16:26:37 +02:00
Dictionary WebRTCMultiplayerPeer : : get_peer ( int p_peer_id ) {
2019-05-11 01:53:49 +02:00
ERR_FAIL_COND_V ( ! peer_map . has ( p_peer_id ) , Dictionary ( ) ) ;
Dictionary out ;
_peer_to_dict ( peer_map [ p_peer_id ] , out ) ;
return out ;
}
2021-07-12 16:26:37 +02:00
Dictionary WebRTCMultiplayerPeer : : get_peers ( ) {
2019-05-11 01:53:49 +02:00
Dictionary out ;
2021-08-09 22:13:42 +02:00
for ( const KeyValue < int , Ref < ConnectedPeer > > & E : peer_map ) {
2019-05-11 01:53:49 +02:00
Dictionary d ;
2021-08-09 22:13:42 +02:00
_peer_to_dict ( E . value , d ) ;
out [ E . key ] = d ;
2019-05-11 01:53:49 +02:00
}
return out ;
}
2021-07-12 16:26:37 +02:00
Error WebRTCMultiplayerPeer : : add_peer ( Ref < WebRTCPeerConnection > p_peer , int p_peer_id , int p_unreliable_lifetime ) {
2022-10-08 20:50:19 +02:00
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 ) ;
2019-05-11 01:53:49 +02:00
ERR_FAIL_COND_V ( p_unreliable_lifetime < 0 , ERR_INVALID_PARAMETER ) ;
2021-09-07 23:04:52 +02:00
ERR_FAIL_COND_V ( is_refusing_new_connections ( ) , ERR_UNAUTHORIZED ) ;
2019-05-11 01:53:49 +02:00
// Peer must be valid, and in new state (to create data channels)
ERR_FAIL_COND_V ( ! p_peer . is_valid ( ) , ERR_INVALID_PARAMETER ) ;
ERR_FAIL_COND_V ( p_peer - > get_connection_state ( ) ! = WebRTCPeerConnection : : STATE_NEW , ERR_INVALID_PARAMETER ) ;
Ref < ConnectedPeer > peer = memnew ( ConnectedPeer ) ;
peer - > connection = p_peer ;
// Initialize data channels
Dictionary cfg ;
cfg [ " negotiated " ] = true ;
cfg [ " ordered " ] = true ;
cfg [ " id " ] = 1 ;
2024-04-15 15:18:34 +02:00
peer - > channels . get ( CH_RELIABLE ) = p_peer - > create_data_channel ( " reliable " , cfg ) ;
ERR_FAIL_COND_V ( peer - > channels . get ( CH_RELIABLE ) . is_null ( ) , FAILED ) ;
2019-05-11 01:53:49 +02:00
cfg [ " id " ] = 2 ;
cfg [ " maxPacketLifetime " ] = p_unreliable_lifetime ;
2024-04-15 15:18:34 +02:00
peer - > channels . get ( CH_ORDERED ) = p_peer - > create_data_channel ( " ordered " , cfg ) ;
ERR_FAIL_COND_V ( peer - > channels . get ( CH_ORDERED ) . is_null ( ) , FAILED ) ;
2019-05-11 01:53:49 +02:00
cfg [ " id " ] = 3 ;
cfg [ " ordered " ] = false ;
2024-04-15 15:18:34 +02:00
peer - > channels . get ( CH_UNRELIABLE ) = p_peer - > create_data_channel ( " unreliable " , cfg ) ;
ERR_FAIL_COND_V ( peer - > channels . get ( CH_UNRELIABLE ) . is_null ( ) , FAILED ) ;
2021-07-27 12:06:48 +02:00
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 ) ;
}
2019-05-11 01:53:49 +02:00
peer_map [ p_peer_id ] = peer ; // add the new peer connection to the peer_map
return OK ;
}
2021-07-12 16:26:37 +02:00
void WebRTCMultiplayerPeer : : remove_peer ( int p_peer_id ) {
2019-05-11 01:53:49 +02:00
ERR_FAIL_COND ( ! peer_map . has ( p_peer_id ) ) ;
Ref < ConnectedPeer > peer = peer_map [ p_peer_id ] ;
peer_map . erase ( p_peer_id ) ;
if ( peer - > connected ) {
peer - > connected = false ;
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " peer_disconnected " ) , p_peer_id ) ;
2022-10-08 20:50:19 +02:00
if ( network_mode = = MODE_CLIENT & & p_peer_id = = TARGET_PEER_SERVER ) {
2019-05-11 01:53:49 +02:00
connection_status = CONNECTION_DISCONNECTED ;
}
}
}
2022-10-22 17:49:40 +02:00
void WebRTCMultiplayerPeer : : disconnect_peer ( int p_peer_id , bool p_force ) {
ERR_FAIL_COND ( ! peer_map . has ( p_peer_id ) ) ;
if ( p_force ) {
peer_map . erase ( p_peer_id ) ;
if ( network_mode = = MODE_CLIENT & & p_peer_id = = TARGET_PEER_SERVER ) {
connection_status = CONNECTION_DISCONNECTED ;
}
} else {
peer_map [ p_peer_id ] - > connection - > close ( ) ; // Will be removed during next poll.
}
}
2021-07-12 16:26:37 +02:00
Error WebRTCMultiplayerPeer : : get_packet ( const uint8_t * * r_buffer , int & r_buffer_size ) {
2019-05-11 01:53:49 +02:00
// Peer not available
if ( next_packet_peer = = 0 | | ! peer_map . has ( next_packet_peer ) ) {
_find_next_peer ( ) ;
ERR_FAIL_V ( ERR_UNAVAILABLE ) ;
}
2021-07-26 17:50:35 +02:00
for ( Ref < WebRTCDataChannel > & E : peer_map [ next_packet_peer ] - > channels ) {
2021-07-16 05:45:57 +02:00
if ( E - > get_available_packet_count ( ) ) {
Error err = E - > get_packet ( r_buffer , r_buffer_size ) ;
2019-05-11 01:53:49 +02:00
_find_next_peer ( ) ;
return err ;
}
}
// Channels for that peer were empty. Bug?
_find_next_peer ( ) ;
ERR_FAIL_V ( ERR_BUG ) ;
}
2021-07-12 16:26:37 +02:00
Error WebRTCMultiplayerPeer : : put_packet ( const uint8_t * p_buffer , int p_buffer_size ) {
2019-05-11 01:53:49 +02:00
ERR_FAIL_COND_V ( connection_status = = CONNECTION_DISCONNECTED , ERR_UNCONFIGURED ) ;
2021-09-07 23:04:52 +02:00
int ch = get_transfer_channel ( ) ;
2021-07-27 12:06:48 +02:00
if ( ch = = 0 ) {
2021-09-07 23:04:52 +02:00
switch ( get_transfer_mode ( ) ) {
2022-07-12 23:12:42 +02:00
case TRANSFER_MODE_RELIABLE :
2021-07-27 12:06:48 +02:00
ch = CH_RELIABLE ;
break ;
2022-07-12 23:12:42 +02:00
case TRANSFER_MODE_UNRELIABLE_ORDERED :
2021-07-27 12:06:48 +02:00
ch = CH_ORDERED ;
break ;
2022-07-12 23:12:42 +02:00
case TRANSFER_MODE_UNRELIABLE :
2021-07-27 12:06:48 +02:00
ch = CH_UNRELIABLE ;
break ;
}
} else {
ch + = CH_RESERVED_MAX - 1 ;
2019-05-11 01:53:49 +02:00
}
if ( target_peer > 0 ) {
2022-05-13 15:04:37 +02:00
HashMap < int , Ref < ConnectedPeer > > : : Iterator E = peer_map . find ( target_peer ) ;
2019-08-11 10:49:53 +02:00
ERR_FAIL_COND_V_MSG ( ! E , ERR_INVALID_PARAMETER , " Invalid target peer: " + itos ( target_peer ) + " . " ) ;
2022-05-13 15:04:37 +02:00
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 ( ) ) ) ;
2024-04-15 15:18:34 +02:00
ERR_FAIL_COND_V ( E - > value - > channels . get ( ch ) . is_null ( ) , ERR_BUG ) ;
return E - > value - > channels . get ( ch ) - > put_packet ( p_buffer , p_buffer_size ) ;
2019-05-11 01:53:49 +02:00
} else {
int exclude = - target_peer ;
2021-08-09 22:13:42 +02:00
for ( KeyValue < int , Ref < ConnectedPeer > > & F : peer_map ) {
2019-05-11 01:53:49 +02:00
// Exclude packet. If target_peer == 0 then don't exclude any packets
2021-08-09 22:13:42 +02:00
if ( target_peer ! = 0 & & F . key = = exclude ) {
2019-05-11 01:53:49 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2019-05-11 01:53:49 +02:00
2022-03-04 16:02:35 +01:00
ERR_CONTINUE_MSG ( F . value - > channels . size ( ) < = ch , vformat ( " Unable to send packet on channel %d, max channels: %d " , ch , F . value - > channels . size ( ) ) ) ;
2024-04-15 15:18:34 +02:00
ERR_CONTINUE ( F . value - > channels . get ( ch ) . is_null ( ) ) ;
F . value - > channels . get ( ch ) - > put_packet ( p_buffer , p_buffer_size ) ;
2019-05-11 01:53:49 +02:00
}
}
return OK ;
}
2021-07-12 16:26:37 +02:00
int WebRTCMultiplayerPeer : : get_available_packet_count ( ) const {
2020-05-14 16:41:43 +02:00
if ( next_packet_peer = = 0 ) {
2019-05-11 01:53:49 +02:00
return 0 ; // To be sure next call to get_packet works if size > 0 .
2020-05-14 16:41:43 +02:00
}
2019-05-11 01:53:49 +02:00
int size = 0 ;
2021-08-09 22:13:42 +02:00
for ( const KeyValue < int , Ref < ConnectedPeer > > & E : peer_map ) {
2021-12-15 10:58:48 +01:00
if ( ! E . value - > connected ) {
continue ;
}
2021-08-09 22:13:42 +02:00
for ( const Ref < WebRTCDataChannel > & F : E . value - > channels ) {
2021-07-16 05:45:57 +02:00
size + = F - > get_available_packet_count ( ) ;
2019-05-11 01:53:49 +02:00
}
}
return size ;
}
2021-07-12 16:26:37 +02:00
int WebRTCMultiplayerPeer : : get_max_packet_size ( ) const {
2019-05-11 01:53:49 +02:00
return 1200 ;
}
2021-07-12 16:26:37 +02:00
void WebRTCMultiplayerPeer : : close ( ) {
2019-05-11 01:53:49 +02:00
peer_map . clear ( ) ;
2021-07-27 12:06:48 +02:00
channels_config . clear ( ) ;
2019-05-11 01:53:49 +02:00
unique_id = 0 ;
next_packet_peer = 0 ;
2022-10-08 20:50:19 +02:00
next_packet_channel = 0 ;
2019-05-11 01:53:49 +02:00
target_peer = 0 ;
2022-10-08 20:50:19 +02:00
network_mode = MODE_NONE ;
2019-05-11 01:53:49 +02:00
connection_status = CONNECTION_DISCONNECTED ;
}
2021-07-12 16:26:37 +02:00
WebRTCMultiplayerPeer : : ~ WebRTCMultiplayerPeer ( ) {
2019-05-11 01:53:49 +02:00
close ( ) ;
}