2016-10-10 19:50:51 +02:00
/*************************************************************************/
/* networked_multiplayer_enet.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 14:16:55 +02:00
/* https://godotengine.org */
2016-10-10 19:50:51 +02:00
/*************************************************************************/
2021-01-01 20:13:46 +01:00
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
2016-10-10 19:50:51 +02:00
/* */
/* 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. */
/*************************************************************************/
2018-01-05 00:50:27 +01:00
2016-08-20 06:05:57 +02:00
# include "networked_multiplayer_enet.h"
2018-09-11 18:13:45 +02:00
# include "core/io/ip.h"
# include "core/io/marshalls.h"
# include "core/os/os.h"
2016-08-14 18:29:25 +02:00
void NetworkedMultiplayerENet : : set_transfer_mode ( TransferMode p_mode ) {
2017-03-05 16:44:50 +01:00
transfer_mode = p_mode ;
2016-08-14 18:29:25 +02:00
}
2018-01-11 23:35:12 +01:00
NetworkedMultiplayerPeer : : TransferMode NetworkedMultiplayerENet : : get_transfer_mode ( ) const {
return transfer_mode ;
}
2016-08-14 18:29:25 +02:00
2017-03-05 16:44:50 +01:00
void NetworkedMultiplayerENet : : set_target_peer ( int p_peer ) {
2016-08-14 18:29:25 +02:00
2017-03-05 16:44:50 +01:00
target_peer = p_peer ;
2016-08-14 18:29:25 +02:00
}
2017-03-05 16:44:50 +01:00
int NetworkedMultiplayerENet : : get_packet_peer ( ) const {
2016-08-14 18:29:25 +02:00
2020-02-02 23:34:47 +01:00
ERR_FAIL_COND_V_MSG ( ! active , 1 , " The multiplayer instance isn't currently active. " ) ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( incoming_packets . size ( ) = = 0 , 1 ) ;
2016-08-14 18:29:25 +02:00
return incoming_packets . front ( ) - > get ( ) . from ;
}
2018-05-12 19:42:00 +02:00
int NetworkedMultiplayerENet : : get_packet_channel ( ) const {
2020-02-02 23:34:47 +01:00
ERR_FAIL_COND_V_MSG ( ! active , - 1 , " The multiplayer instance isn't currently active. " ) ;
2018-05-12 19:42:00 +02:00
ERR_FAIL_COND_V ( incoming_packets . size ( ) = = 0 , - 1 ) ;
return incoming_packets . front ( ) - > get ( ) . channel ;
}
int NetworkedMultiplayerENet : : get_last_packet_channel ( ) const {
2020-02-02 23:34:47 +01:00
ERR_FAIL_COND_V_MSG ( ! active , - 1 , " The multiplayer instance isn't currently active. " ) ;
2018-05-12 19:42:00 +02:00
ERR_FAIL_COND_V ( ! current_packet . packet , - 1 ) ;
return current_packet . channel ;
}
2017-03-05 16:44:50 +01:00
Error NetworkedMultiplayerENet : : create_server ( int p_port , int p_max_clients , int p_in_bandwidth , int p_out_bandwidth ) {
2016-08-14 18:29:25 +02:00
2020-02-02 23:34:47 +01:00
ERR_FAIL_COND_V_MSG ( active , ERR_ALREADY_IN_USE , " The multiplayer instance is already active. " ) ;
ERR_FAIL_COND_V_MSG ( p_port < 0 | | p_port > 65535 , ERR_INVALID_PARAMETER , " The port number must be set between 0 and 65535 (inclusive). " ) ;
ERR_FAIL_COND_V_MSG ( p_max_clients < 1 | | p_max_clients > 4095 , ERR_INVALID_PARAMETER , " The number of clients must be set between 1 and 4095 (inclusive). " ) ;
ERR_FAIL_COND_V_MSG ( p_in_bandwidth < 0 , ERR_INVALID_PARAMETER , " The incoming bandwidth limit must be greater than or equal to 0 (0 disables the limit). " ) ;
ERR_FAIL_COND_V_MSG ( p_out_bandwidth < 0 , ERR_INVALID_PARAMETER , " The outgoing bandwidth limit must be greater than or equal to 0 (0 disables the limit). " ) ;
2020-01-13 16:51:17 +01:00
ERR_FAIL_COND_V ( dtls_enabled & & ( dtls_key . is_null ( ) | | dtls_cert . is_null ( ) ) , ERR_INVALID_PARAMETER ) ;
2016-08-14 18:29:25 +02:00
ENetAddress address ;
2019-06-15 05:55:41 +02:00
memset ( & address , 0 , sizeof ( address ) ) ;
2016-08-19 21:48:08 +02:00
2017-01-22 06:00:59 +01:00
# ifdef GODOT_ENET
if ( bind_ip . is_wildcard ( ) ) {
address . wildcard = 1 ;
} else {
enet_address_set_ip ( & address , bind_ip . get_ipv6 ( ) , 16 ) ;
}
# else
if ( bind_ip . is_wildcard ( ) ) {
address . host = 0 ;
} else {
ERR_FAIL_COND_V ( ! bind_ip . is_ipv4 ( ) , ERR_INVALID_PARAMETER ) ;
address . host = * ( uint32_t * ) bind_ip . get_ipv4 ( ) ;
}
# endif
2016-08-19 21:48:08 +02:00
address . port = p_port ;
2016-08-14 18:29:25 +02:00
2017-03-05 16:44:50 +01:00
host = enet_host_create ( & address /* the address to bind the server host to */ ,
p_max_clients /* allow up to 32 clients and/or outgoing connections */ ,
2018-05-12 19:42:00 +02:00
channel_count /* allow up to channel_count to be used */ ,
2018-09-13 03:38:39 +02:00
p_in_bandwidth /* limit incoming bandwidth if > 0 */ ,
p_out_bandwidth /* limit outgoing bandwidth if > 0 */ ) ;
2016-08-14 18:29:25 +02:00
2020-02-02 23:34:47 +01:00
ERR_FAIL_COND_V_MSG ( ! host , ERR_CANT_CREATE , " Couldn't create an ENet multiplayer server. " ) ;
2020-01-13 16:51:17 +01:00
# ifdef GODOT_ENET
if ( dtls_enabled ) {
enet_host_dtls_server_setup ( host , dtls_key . ptr ( ) , dtls_cert . ptr ( ) ) ;
}
2020-07-23 10:38:48 +02:00
enet_host_refuse_new_connections ( host , refuse_connections ) ;
2020-01-13 16:51:17 +01:00
# endif
2016-08-14 18:29:25 +02:00
2016-08-22 06:14:08 +02:00
_setup_compressor ( ) ;
2017-03-05 16:44:50 +01:00
active = true ;
server = true ;
refuse_connections = false ;
unique_id = 1 ;
connection_status = CONNECTION_CONNECTED ;
2016-08-14 18:29:25 +02:00
return OK ;
}
2018-05-07 00:28:59 +02:00
Error NetworkedMultiplayerENet : : create_client ( const String & p_address , int p_port , int p_in_bandwidth , int p_out_bandwidth , int p_client_port ) {
2016-08-14 18:29:25 +02:00
2020-02-02 23:34:47 +01:00
ERR_FAIL_COND_V_MSG ( active , ERR_ALREADY_IN_USE , " The multiplayer instance is already active. " ) ;
ERR_FAIL_COND_V_MSG ( p_port < 0 | | p_port > 65535 , ERR_INVALID_PARAMETER , " The server port number must be set between 0 and 65535 (inclusive). " ) ;
ERR_FAIL_COND_V_MSG ( p_client_port < 0 | | p_client_port > 65535 , ERR_INVALID_PARAMETER , " The client port number must be set between 0 and 65535 (inclusive). " ) ;
ERR_FAIL_COND_V_MSG ( p_in_bandwidth < 0 , ERR_INVALID_PARAMETER , " The incoming bandwidth limit must be greater than or equal to 0 (0 disables the limit). " ) ;
ERR_FAIL_COND_V_MSG ( p_out_bandwidth < 0 , ERR_INVALID_PARAMETER , " The outgoing bandwidth limit must be greater than or equal to 0 (0 disables the limit). " ) ;
2016-08-14 18:29:25 +02:00
2018-05-07 00:28:59 +02:00
if ( p_client_port ! = 0 ) {
ENetAddress c_client ;
# ifdef GODOT_ENET
if ( bind_ip . is_wildcard ( ) ) {
c_client . wildcard = 1 ;
} else {
enet_address_set_ip ( & c_client , bind_ip . get_ipv6 ( ) , 16 ) ;
}
# else
if ( bind_ip . is_wildcard ( ) ) {
c_client . host = 0 ;
} else {
2020-02-02 23:34:47 +01:00
ERR_FAIL_COND_V_MSG ( ! bind_ip . is_ipv4 ( ) , ERR_INVALID_PARAMETER , " Wildcard IP addresses are only permitted in IPv4, not IPv6. " ) ;
2018-05-07 00:28:59 +02:00
c_client . host = * ( uint32_t * ) bind_ip . get_ipv4 ( ) ;
}
# endif
c_client . port = p_client_port ;
host = enet_host_create ( & c_client /* create a client host */ ,
1 /* only allow 1 outgoing connection */ ,
2018-05-12 19:42:00 +02:00
channel_count /* allow up to channel_count to be used */ ,
2018-09-13 03:38:39 +02:00
p_in_bandwidth /* limit incoming bandwidth if > 0 */ ,
p_out_bandwidth /* limit outgoing bandwidth if > 0 */ ) ;
2018-05-07 00:28:59 +02:00
} else {
host = enet_host_create ( NULL /* create a client host */ ,
1 /* only allow 1 outgoing connection */ ,
2018-05-12 19:42:00 +02:00
channel_count /* allow up to channel_count to be used */ ,
2018-09-13 03:38:39 +02:00
p_in_bandwidth /* limit incoming bandwidth if > 0 */ ,
p_out_bandwidth /* limit outgoing bandwidth if > 0 */ ) ;
2018-05-07 00:28:59 +02:00
}
2016-08-14 19:06:51 +02:00
2020-02-02 23:34:47 +01:00
ERR_FAIL_COND_V_MSG ( ! host , ERR_CANT_CREATE , " Couldn't create the ENet client host. " ) ;
2020-01-13 16:51:17 +01:00
# ifdef GODOT_ENET
if ( dtls_enabled ) {
enet_host_dtls_client_setup ( host , dtls_cert . ptr ( ) , dtls_verify , p_address . utf8 ( ) . get_data ( ) ) ;
}
2020-07-23 10:38:48 +02:00
enet_host_refuse_new_connections ( host , refuse_connections ) ;
2020-01-13 16:51:17 +01:00
# endif
2016-08-14 19:06:51 +02:00
2016-08-22 06:14:08 +02:00
_setup_compressor ( ) ;
2018-04-12 20:36:26 +02:00
IP_Address ip ;
if ( p_address . is_valid_ip_address ( ) ) {
ip = p_address ;
} else {
# ifdef GODOT_ENET
ip = IP : : get_singleton ( ) - > resolve_hostname ( p_address ) ;
# else
ip = IP : : get_singleton ( ) - > resolve_hostname ( p_address , IP : : TYPE_IPV4 ) ;
# endif
2020-02-02 23:34:47 +01:00
ERR_FAIL_COND_V_MSG ( ! ip . is_valid ( ) , ERR_CANT_RESOLVE , " Couldn't resolve the server IP address or domain name. " ) ;
2018-04-12 20:36:26 +02:00
}
2016-08-14 19:06:51 +02:00
ENetAddress address ;
2017-01-22 06:00:59 +01:00
# ifdef GODOT_ENET
2018-04-12 20:36:26 +02:00
enet_address_set_ip ( & address , ip . get_ipv6 ( ) , 16 ) ;
2017-01-22 06:00:59 +01:00
# else
2020-02-02 23:34:47 +01:00
ERR_FAIL_COND_V_MSG ( ! ip . is_ipv4 ( ) , ERR_INVALID_PARAMETER , " Connecting to an IPv6 server isn't supported when using vanilla ENet. Recompile Godot with the bundled ENet library. " ) ;
2018-04-12 20:36:26 +02:00
address . host = * ( uint32_t * ) ip . get_ipv4 ( ) ;
2017-01-22 06:00:59 +01:00
# endif
2017-03-05 16:44:50 +01:00
address . port = p_port ;
2016-08-14 19:06:51 +02:00
2017-03-05 16:44:50 +01:00
unique_id = _gen_unique_id ( ) ;
2016-08-19 21:48:08 +02:00
2018-05-07 00:28:59 +02:00
// Initiate connection, allocating enough channels
2018-05-12 19:42:00 +02:00
ENetPeer * peer = enet_host_connect ( host , & address , channel_count , unique_id ) ;
2016-08-14 19:06:51 +02:00
if ( peer = = NULL ) {
enet_host_destroy ( host ) ;
2020-02-02 23:34:47 +01:00
ERR_FAIL_COND_V_MSG ( ! peer , ERR_CANT_CREATE , " Couldn't connect to the ENet multiplayer server. " ) ;
2016-08-14 19:06:51 +02:00
}
2018-04-08 22:45:14 +02:00
// Technically safe to ignore the peer or anything else.
2016-08-14 19:06:51 +02:00
2017-03-05 16:44:50 +01:00
connection_status = CONNECTION_CONNECTING ;
active = true ;
server = false ;
refuse_connections = false ;
2016-08-14 18:29:25 +02:00
return OK ;
}
2017-03-05 16:44:50 +01:00
void NetworkedMultiplayerENet : : poll ( ) {
2016-08-14 18:29:25 +02:00
2020-02-02 23:34:47 +01:00
ERR_FAIL_COND_MSG ( ! active , " The multiplayer instance isn't currently active. " ) ;
2016-08-14 18:29:25 +02:00
_pop_current_packet ( ) ;
ENetEvent event ;
2018-09-25 16:26:45 +02:00
/* Keep servicing until there are no available events left in queue. */
2016-08-19 21:48:08 +02:00
while ( true ) {
2018-04-08 22:45:14 +02:00
if ( ! host | | ! active ) // Might have been disconnected while emitting a notification
2016-08-19 21:48:08 +02:00
return ;
2018-09-25 16:26:45 +02:00
int ret = enet_host_service ( host , & event , 0 ) ;
2016-08-19 21:48:08 +02:00
2017-03-05 16:44:50 +01:00
if ( ret < 0 ) {
2018-04-08 22:45:14 +02:00
// Error, do something?
2016-08-19 21:48:08 +02:00
break ;
2017-03-05 16:44:50 +01:00
} else if ( ret = = 0 ) {
2016-08-19 21:48:08 +02:00
break ;
}
2017-03-05 16:44:50 +01:00
switch ( event . type ) {
2016-08-14 18:29:25 +02:00
case ENET_EVENT_TYPE_CONNECT : {
2018-05-07 00:28:59 +02:00
// Store any relevant client information here.
2016-08-14 18:29:25 +02:00
2016-08-19 21:48:08 +02:00
if ( server & & refuse_connections ) {
enet_peer_reset ( event . peer ) ;
break ;
}
2019-05-19 12:34:40 +02:00
// A client joined with an invalid ID (negative values, 0, and 1 are reserved).
2019-02-20 16:28:53 +01:00
// Probably trying to exploit us.
if ( server & & ( ( int ) event . data < 2 | | peer_map . has ( ( int ) event . data ) ) ) {
enet_peer_reset ( event . peer ) ;
ERR_CONTINUE ( true ) ;
}
2017-03-05 16:44:50 +01:00
int * new_id = memnew ( int ) ;
2016-08-19 21:48:08 +02:00
* new_id = event . data ;
2018-05-07 00:28:59 +02:00
if ( * new_id = = 0 ) { // Data zero is sent by server (enet won't let you configure this). Server is always 1.
2017-03-05 16:44:50 +01:00
* new_id = 1 ;
2016-08-19 21:48:08 +02:00
}
2017-03-05 16:44:50 +01:00
event . peer - > data = new_id ;
2016-08-14 18:29:25 +02:00
2017-03-05 16:44:50 +01:00
peer_map [ * new_id ] = event . peer ;
2016-08-14 18:29:25 +02:00
2018-04-08 22:45:14 +02:00
connection_status = CONNECTION_CONNECTED ; // If connecting, this means it connected to something!
2016-08-14 19:06:51 +02:00
2017-03-05 16:44:50 +01:00
emit_signal ( " peer_connected " , * new_id ) ;
2016-08-14 18:29:25 +02:00
2016-08-19 21:48:08 +02:00
if ( server ) {
2019-11-26 17:21:19 +01:00
// Do not notify other peers when server_relay is disabled.
if ( ! server_relay )
break ;
2018-04-08 22:45:14 +02:00
// Someone connected, notify all the peers available
2017-03-05 16:44:50 +01:00
for ( Map < int , ENetPeer * > : : Element * E = peer_map . front ( ) ; E ; E = E - > next ( ) ) {
2016-08-19 21:48:08 +02:00
2017-03-05 16:44:50 +01:00
if ( E - > key ( ) = = * new_id )
2016-08-19 21:48:08 +02:00
continue ;
2018-04-08 22:45:14 +02:00
// Send existing peers to new peer
2017-03-05 16:44:50 +01:00
ENetPacket * packet = enet_packet_create ( NULL , 8 , ENET_PACKET_FLAG_RELIABLE ) ;
encode_uint32 ( SYSMSG_ADD_PEER , & packet - > data [ 0 ] ) ;
encode_uint32 ( E - > key ( ) , & packet - > data [ 4 ] ) ;
enet_peer_send ( event . peer , SYSCH_CONFIG , packet ) ;
2018-04-08 22:45:14 +02:00
// Send the new peer to existing peers
2017-03-05 16:44:50 +01:00
packet = enet_packet_create ( NULL , 8 , ENET_PACKET_FLAG_RELIABLE ) ;
encode_uint32 ( SYSMSG_ADD_PEER , & packet - > data [ 0 ] ) ;
encode_uint32 ( * new_id , & packet - > data [ 4 ] ) ;
enet_peer_send ( E - > get ( ) , SYSCH_CONFIG , packet ) ;
2016-08-19 21:48:08 +02:00
}
} else {
emit_signal ( " connection_succeeded " ) ;
}
2016-08-14 18:29:25 +02:00
} break ;
case ENET_EVENT_TYPE_DISCONNECT : {
2018-05-07 00:28:59 +02:00
// Reset the peer's client information.
2016-08-14 18:29:25 +02:00
2017-03-05 16:44:50 +01:00
int * id = ( int * ) event . peer - > data ;
2016-08-19 21:48:08 +02:00
if ( ! id ) {
if ( ! server ) {
emit_signal ( " connection_failed " ) ;
}
2019-11-26 17:21:19 +01:00
// Never fully connected.
break ;
}
2016-08-19 21:48:08 +02:00
2019-11-26 17:21:19 +01:00
if ( ! server ) {
2016-08-19 21:48:08 +02:00
2019-11-26 17:21:19 +01:00
// Client just disconnected from server.
emit_signal ( " server_disconnected " ) ;
close_connection ( ) ;
return ;
} else if ( server_relay ) {
2018-04-08 22:45:14 +02:00
2019-11-26 17:21:19 +01:00
// Server just received a client disconnect and is in relay mode, notify everyone else.
for ( Map < int , ENetPeer * > : : Element * E = peer_map . front ( ) ; E ; E = E - > next ( ) ) {
if ( E - > key ( ) = = * id )
continue ;
2016-08-19 21:48:08 +02:00
2019-11-26 17:21:19 +01:00
ENetPacket * packet = enet_packet_create ( NULL , 8 , ENET_PACKET_FLAG_RELIABLE ) ;
encode_uint32 ( SYSMSG_REMOVE_PEER , & packet - > data [ 0 ] ) ;
encode_uint32 ( * id , & packet - > data [ 4 ] ) ;
enet_peer_send ( E - > get ( ) , SYSCH_CONFIG , packet ) ;
}
2016-08-19 21:48:08 +02:00
}
2016-08-14 18:29:25 +02:00
2019-11-26 17:21:19 +01:00
emit_signal ( " peer_disconnected " , * id ) ;
peer_map . erase ( * id ) ;
memdelete ( id ) ;
2016-08-14 18:29:25 +02:00
} break ;
case ENET_EVENT_TYPE_RECEIVE : {
2017-03-05 16:44:50 +01:00
if ( event . channelID = = SYSCH_CONFIG ) {
2018-04-08 22:45:14 +02:00
// Some config message
2017-03-05 16:44:50 +01:00
ERR_CONTINUE ( event . packet - > dataLength < 8 ) ;
2016-08-19 21:48:08 +02:00
2016-10-07 16:44:53 +02:00
// Only server can send config messages
2017-03-05 16:44:50 +01:00
ERR_CONTINUE ( server ) ;
2016-10-07 16:44:53 +02:00
2016-08-19 21:48:08 +02:00
int msg = decode_uint32 ( & event . packet - > data [ 0 ] ) ;
int id = decode_uint32 ( & event . packet - > data [ 4 ] ) ;
2017-03-05 16:44:50 +01:00
switch ( msg ) {
2016-08-19 21:48:08 +02:00
case SYSMSG_ADD_PEER : {
2017-03-05 16:44:50 +01:00
peer_map [ id ] = NULL ;
emit_signal ( " peer_connected " , id ) ;
2016-08-19 21:48:08 +02:00
} break ;
case SYSMSG_REMOVE_PEER : {
peer_map . erase ( id ) ;
2017-03-05 16:44:50 +01:00
emit_signal ( " peer_disconnected " , id ) ;
2016-08-19 21:48:08 +02:00
} break ;
}
enet_packet_destroy ( event . packet ) ;
2018-05-12 19:42:00 +02:00
} else if ( event . channelID < channel_count ) {
2016-08-19 21:48:08 +02:00
Packet packet ;
packet . packet = event . packet ;
2017-03-05 16:44:50 +01:00
uint32_t * id = ( uint32_t * ) event . peer - > data ;
2016-08-19 21:48:08 +02:00
2019-06-11 14:49:34 +02:00
ERR_CONTINUE ( event . packet - > dataLength < 8 ) ;
2016-08-19 21:48:08 +02:00
uint32_t source = decode_uint32 ( & event . packet - > data [ 0 ] ) ;
int target = decode_uint32 ( & event . packet - > data [ 4 ] ) ;
2017-03-05 16:44:50 +01:00
packet . from = source ;
2018-05-12 19:42:00 +02:00
packet . channel = event . channelID ;
2016-08-19 21:48:08 +02:00
if ( server ) {
2016-10-07 16:44:53 +02:00
// Someone is cheating and trying to fake the source!
2017-03-05 16:44:50 +01:00
ERR_CONTINUE ( source ! = * id ) ;
2016-08-19 21:48:08 +02:00
2017-03-05 16:44:50 +01:00
packet . from = * id ;
2016-08-19 21:48:08 +02:00
2019-11-26 17:21:19 +01:00
if ( target = = 1 ) {
// To myself and only myself
incoming_packets . push_back ( packet ) ;
} else if ( ! server_relay ) {
// No other destination is allowed when server is not relaying
continue ;
} else if ( target = = 0 ) {
2018-04-08 22:45:14 +02:00
// Re-send to everyone but sender :|
2016-08-19 21:48:08 +02:00
incoming_packets . push_back ( packet ) ;
2018-04-08 22:45:14 +02:00
// And make copies for sending
2017-03-05 16:44:50 +01:00
for ( Map < int , ENetPeer * > : : Element * E = peer_map . front ( ) ; E ; E = E - > next ( ) ) {
2016-08-19 21:48:08 +02:00
2018-04-08 22:45:14 +02:00
if ( uint32_t ( E - > key ( ) ) = = source ) // Do not resend to self
2016-08-19 21:48:08 +02:00
continue ;
2019-01-15 08:32:17 +01:00
ENetPacket * packet2 = enet_packet_create ( packet . packet - > data , packet . packet - > dataLength , packet . packet - > flags ) ;
2016-08-19 21:48:08 +02:00
2017-03-05 16:44:50 +01:00
enet_peer_send ( E - > get ( ) , event . channelID , packet2 ) ;
2016-08-19 21:48:08 +02:00
}
2017-03-05 16:44:50 +01:00
} else if ( target < 0 ) {
2018-04-08 22:45:14 +02:00
// To all but one
2016-08-19 21:48:08 +02:00
2018-04-08 22:45:14 +02:00
// And make copies for sending
2017-03-05 16:44:50 +01:00
for ( Map < int , ENetPeer * > : : Element * E = peer_map . front ( ) ; E ; E = E - > next ( ) ) {
2016-08-19 21:48:08 +02:00
2018-04-08 22:45:14 +02:00
if ( uint32_t ( E - > key ( ) ) = = source | | E - > key ( ) = = - target ) // Do not resend to self, also do not send to excluded
2016-08-19 21:48:08 +02:00
continue ;
2019-01-15 08:32:17 +01:00
ENetPacket * packet2 = enet_packet_create ( packet . packet - > data , packet . packet - > dataLength , packet . packet - > flags ) ;
2016-08-19 21:48:08 +02:00
2017-03-05 16:44:50 +01:00
enet_peer_send ( E - > get ( ) , event . channelID , packet2 ) ;
2016-08-19 21:48:08 +02:00
}
if ( - target ! = 1 ) {
2018-04-08 22:45:14 +02:00
// Server is not excluded
2016-08-19 21:48:08 +02:00
incoming_packets . push_back ( packet ) ;
} else {
2018-04-08 22:45:14 +02:00
// Server is excluded, erase packet
2016-08-19 21:48:08 +02:00
enet_packet_destroy ( packet . packet ) ;
}
} else {
2018-04-08 22:45:14 +02:00
// To someone else, specifically
2016-08-19 23:44:09 +02:00
ERR_CONTINUE ( ! peer_map . has ( target ) ) ;
2017-03-05 16:44:50 +01:00
enet_peer_send ( peer_map [ target ] , event . channelID , packet . packet ) ;
2016-08-19 21:48:08 +02:00
}
} else {
incoming_packets . push_back ( packet ) ;
}
2018-05-07 00:28:59 +02:00
// Destroy packet later
2016-08-19 21:48:08 +02:00
} else {
ERR_CONTINUE ( true ) ;
}
2016-08-14 18:29:25 +02:00
2017-03-05 16:44:50 +01:00
} break ;
2016-08-14 19:06:51 +02:00
case ENET_EVENT_TYPE_NONE : {
2018-04-08 22:45:14 +02:00
// Do nothing
2016-08-14 19:06:51 +02:00
} break ;
2016-08-14 18:29:25 +02:00
}
}
}
2016-08-14 23:49:50 +02:00
bool NetworkedMultiplayerENet : : is_server ( ) const {
2020-02-02 23:34:47 +01:00
ERR_FAIL_COND_V_MSG ( ! active , false , " The multiplayer instance isn't currently active. " ) ;
2016-08-14 23:49:50 +02:00
return server ;
}
2018-05-07 00:28:59 +02:00
void NetworkedMultiplayerENet : : close_connection ( uint32_t wait_usec ) {
2016-08-14 18:29:25 +02:00
2020-02-02 23:34:47 +01:00
ERR_FAIL_COND_MSG ( ! active , " The multiplayer instance isn't currently active. " ) ;
2016-08-14 18:29:25 +02:00
_pop_current_packet ( ) ;
2017-03-05 16:44:50 +01:00
bool peers_disconnected = false ;
for ( Map < int , ENetPeer * > : : Element * E = peer_map . front ( ) ; E ; E = E - > next ( ) ) {
2016-08-19 21:48:08 +02:00
if ( E - > get ( ) ) {
2017-03-05 16:44:50 +01:00
enet_peer_disconnect_now ( E - > get ( ) , unique_id ) ;
2019-11-26 15:28:20 +01:00
int * id = ( int * ) ( E - > get ( ) - > data ) ;
memdelete ( id ) ;
2017-03-05 16:44:50 +01:00
peers_disconnected = true ;
2016-08-19 21:48:08 +02:00
}
}
if ( peers_disconnected ) {
enet_host_flush ( host ) ;
2018-05-07 00:28:59 +02:00
if ( wait_usec > 0 ) {
OS : : get_singleton ( ) - > delay_usec ( wait_usec ) ; // Wait for disconnection packets to send
}
2016-08-19 21:48:08 +02:00
}
2016-08-14 18:29:25 +02:00
enet_host_destroy ( host ) ;
2017-03-05 16:44:50 +01:00
active = false ;
2016-08-14 18:29:25 +02:00
incoming_packets . clear ( ) ;
2019-11-26 15:28:20 +01:00
peer_map . clear ( ) ;
2018-04-08 22:45:14 +02:00
unique_id = 1 ; // Server is 1
2017-03-05 16:44:50 +01:00
connection_status = CONNECTION_DISCONNECTED ;
2016-08-14 18:29:25 +02:00
}
2018-04-08 22:45:14 +02:00
void NetworkedMultiplayerENet : : disconnect_peer ( int p_peer , bool now ) {
2020-02-02 23:34:47 +01:00
ERR_FAIL_COND_MSG ( ! active , " The multiplayer instance isn't currently active. " ) ;
ERR_FAIL_COND_MSG ( ! is_server ( ) , " Can't disconnect a peer when not acting as a server. " ) ;
ERR_FAIL_COND_MSG ( ! peer_map . has ( p_peer ) , vformat ( " Peer ID %d not found in the list of peers. " , p_peer ) ) ;
2018-04-08 22:45:14 +02:00
if ( now ) {
2020-01-03 20:09:49 +01:00
int * id = ( int * ) peer_map [ p_peer ] - > data ;
2018-04-08 22:45:14 +02:00
enet_peer_disconnect_now ( peer_map [ p_peer ] , 0 ) ;
// enet_peer_disconnect_now doesn't generate ENET_EVENT_TYPE_DISCONNECT,
// notify everyone else, send disconnect signal & remove from peer_map like in poll()
2020-01-03 20:09:49 +01:00
if ( server_relay ) {
for ( Map < int , ENetPeer * > : : Element * E = peer_map . front ( ) ; E ; E = E - > next ( ) ) {
2018-04-08 22:45:14 +02:00
2020-01-03 20:09:49 +01:00
if ( E - > key ( ) = = p_peer ) {
continue ;
}
2018-04-08 22:45:14 +02:00
2020-01-03 20:09:49 +01:00
ENetPacket * packet = enet_packet_create ( NULL , 8 , ENET_PACKET_FLAG_RELIABLE ) ;
encode_uint32 ( SYSMSG_REMOVE_PEER , & packet - > data [ 0 ] ) ;
encode_uint32 ( p_peer , & packet - > data [ 4 ] ) ;
enet_peer_send ( E - > get ( ) , SYSCH_CONFIG , packet ) ;
2019-11-26 15:28:20 +01:00
}
2018-04-08 22:45:14 +02:00
}
2019-11-26 15:28:20 +01:00
if ( id )
memdelete ( id ) ;
2018-04-08 22:45:14 +02:00
emit_signal ( " peer_disconnected " , p_peer ) ;
peer_map . erase ( p_peer ) ;
} else {
enet_peer_disconnect_later ( peer_map [ p_peer ] , 0 ) ;
}
}
2016-08-14 18:29:25 +02:00
int NetworkedMultiplayerENet : : get_available_packet_count ( ) const {
return incoming_packets . size ( ) ;
}
2018-05-07 00:28:59 +02:00
2017-12-15 16:05:42 +01:00
Error NetworkedMultiplayerENet : : get_packet ( const uint8_t * * r_buffer , int & r_buffer_size ) {
2016-08-14 18:29:25 +02:00
2020-02-02 23:34:47 +01:00
ERR_FAIL_COND_V_MSG ( incoming_packets . size ( ) = = 0 , ERR_UNAVAILABLE , " No incoming packets available. " ) ;
2016-08-14 18:29:25 +02:00
_pop_current_packet ( ) ;
current_packet = incoming_packets . front ( ) - > get ( ) ;
incoming_packets . pop_front ( ) ;
2019-01-15 08:32:17 +01:00
* r_buffer = ( const uint8_t * ) ( & current_packet . packet - > data [ 8 ] ) ;
r_buffer_size = current_packet . packet - > dataLength - 8 ;
2016-08-14 18:29:25 +02:00
return OK ;
}
2018-05-07 00:28:59 +02:00
2017-03-05 16:44:50 +01:00
Error NetworkedMultiplayerENet : : put_packet ( const uint8_t * p_buffer , int p_buffer_size ) {
2016-08-14 18:29:25 +02:00
2020-02-02 23:34:47 +01:00
ERR_FAIL_COND_V_MSG ( ! active , ERR_UNCONFIGURED , " The multiplayer instance isn't currently active. " ) ;
ERR_FAIL_COND_V_MSG ( connection_status ! = CONNECTION_CONNECTED , ERR_UNCONFIGURED , " The multiplayer instance isn't currently connected to any server or client. " ) ;
2016-08-14 18:29:25 +02:00
2017-03-05 16:44:50 +01:00
int packet_flags = 0 ;
int channel = SYSCH_RELIABLE ;
2016-08-19 21:48:08 +02:00
2017-03-05 16:44:50 +01:00
switch ( transfer_mode ) {
2016-08-14 18:29:25 +02:00
case TRANSFER_MODE_UNRELIABLE : {
2018-05-12 19:42:00 +02:00
if ( always_ordered )
packet_flags = 0 ;
else
packet_flags = ENET_PACKET_FLAG_UNSEQUENCED ;
2017-03-05 16:44:50 +01:00
channel = SYSCH_UNRELIABLE ;
2016-08-14 18:29:25 +02:00
} break ;
2016-08-20 03:54:02 +02:00
case TRANSFER_MODE_UNRELIABLE_ORDERED : {
2017-03-05 16:44:50 +01:00
packet_flags = 0 ;
channel = SYSCH_UNRELIABLE ;
2016-08-14 18:29:25 +02:00
} break ;
2016-08-20 03:54:02 +02:00
case TRANSFER_MODE_RELIABLE : {
2017-03-05 16:44:50 +01:00
packet_flags = ENET_PACKET_FLAG_RELIABLE ;
channel = SYSCH_RELIABLE ;
2016-08-14 18:29:25 +02:00
} break ;
}
2018-05-12 19:42:00 +02:00
if ( transfer_channel > SYSCH_CONFIG )
channel = transfer_channel ;
2017-03-05 16:44:50 +01:00
Map < int , ENetPeer * > : : Element * E = NULL ;
2016-08-19 21:48:08 +02:00
2017-03-05 16:44:50 +01:00
if ( target_peer ! = 0 ) {
2016-08-19 21:48:08 +02:00
E = peer_map . find ( ABS ( target_peer ) ) ;
2020-02-02 23:34:47 +01:00
ERR_FAIL_COND_V_MSG ( ! E , ERR_INVALID_PARAMETER , vformat ( " Invalid target peer: %d " , target_peer ) ) ;
2016-08-19 21:48:08 +02:00
}
2019-01-15 08:32:17 +01:00
ENetPacket * packet = enet_packet_create ( NULL , p_buffer_size + 8 , packet_flags ) ;
2018-04-08 22:45:14 +02:00
encode_uint32 ( unique_id , & packet - > data [ 0 ] ) ; // Source ID
encode_uint32 ( target_peer , & packet - > data [ 4 ] ) ; // Dest ID
2021-04-29 12:34:11 +02:00
memcpy ( & packet - > data [ 8 ] , p_buffer , p_buffer_size ) ;
2016-08-19 21:48:08 +02:00
if ( server ) {
2017-03-05 16:44:50 +01:00
if ( target_peer = = 0 ) {
enet_host_broadcast ( host , channel , packet ) ;
} else if ( target_peer < 0 ) {
2018-04-08 22:45:14 +02:00
// Send to all but one
// and make copies for sending
2016-08-19 21:48:08 +02:00
2017-03-05 16:44:50 +01:00
int exclude = - target_peer ;
2016-08-19 21:48:08 +02:00
2017-03-05 16:44:50 +01:00
for ( Map < int , ENetPeer * > : : Element * F = peer_map . front ( ) ; F ; F = F - > next ( ) ) {
2016-08-19 21:48:08 +02:00
2018-04-08 22:45:14 +02:00
if ( F - > key ( ) = = exclude ) // Exclude packet
2016-08-19 21:48:08 +02:00
continue ;
2016-08-14 18:29:25 +02:00
2017-03-05 16:44:50 +01:00
ENetPacket * packet2 = enet_packet_create ( packet - > data , packet - > dataLength , packet_flags ) ;
2016-08-19 21:48:08 +02:00
2017-03-05 16:44:50 +01:00
enet_peer_send ( F - > get ( ) , channel , packet2 ) ;
2016-08-19 21:48:08 +02:00
}
2018-04-08 22:45:14 +02:00
enet_packet_destroy ( packet ) ; // Original packet no longer needed
2016-08-19 21:48:08 +02:00
} else {
2017-03-05 16:44:50 +01:00
enet_peer_send ( E - > get ( ) , channel , packet ) ;
2016-08-19 21:48:08 +02:00
}
2016-08-14 18:29:25 +02:00
} else {
2016-08-19 21:48:08 +02:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! peer_map . has ( 1 ) , ERR_BUG ) ;
2018-05-07 00:28:59 +02:00
enet_peer_send ( peer_map [ 1 ] , channel , packet ) ; // Send to server for broadcast
2016-08-14 18:29:25 +02:00
}
enet_host_flush ( host ) ;
return OK ;
}
int NetworkedMultiplayerENet : : get_max_packet_size ( ) const {
2018-04-08 22:45:14 +02:00
return 1 < < 24 ; // Anything is good
2016-08-14 18:29:25 +02:00
}
2017-12-15 16:05:42 +01:00
void NetworkedMultiplayerENet : : _pop_current_packet ( ) {
2016-08-14 18:29:25 +02:00
if ( current_packet . packet ) {
enet_packet_destroy ( current_packet . packet ) ;
2017-03-05 16:44:50 +01:00
current_packet . packet = NULL ;
current_packet . from = 0 ;
2018-05-12 19:42:00 +02:00
current_packet . channel = - 1 ;
2016-08-14 18:29:25 +02:00
}
}
2016-08-14 19:06:51 +02:00
NetworkedMultiplayerPeer : : ConnectionStatus NetworkedMultiplayerENet : : get_connection_status ( ) const {
return connection_status ;
}
2016-08-19 21:48:08 +02:00
uint32_t NetworkedMultiplayerENet : : _gen_unique_id ( ) const {
uint32_t hash = 0 ;
2017-03-05 16:44:50 +01:00
while ( hash = = 0 | | hash = = 1 ) {
2016-08-19 21:48:08 +02:00
hash = hash_djb2_one_32 (
2017-03-05 16:44:50 +01:00
( uint32_t ) OS : : get_singleton ( ) - > get_ticks_usec ( ) ) ;
2016-08-19 21:48:08 +02:00
hash = hash_djb2_one_32 (
2017-03-05 16:44:50 +01:00
( uint32_t ) OS : : get_singleton ( ) - > get_unix_time ( ) , hash ) ;
2016-08-19 21:48:08 +02:00
hash = hash_djb2_one_32 (
2017-11-17 15:25:22 +01:00
( uint32_t ) OS : : get_singleton ( ) - > get_user_data_dir ( ) . hash64 ( ) , hash ) ;
2016-08-19 21:48:08 +02:00
hash = hash_djb2_one_32 (
2018-04-08 22:45:14 +02:00
( uint32_t ) ( ( uint64_t ) this ) , hash ) ; // Rely on ASLR heap
2016-08-19 21:48:08 +02:00
hash = hash_djb2_one_32 (
2018-04-08 22:45:14 +02:00
( uint32_t ) ( ( uint64_t ) & hash ) , hash ) ; // Rely on ASLR stack
2016-08-19 21:48:08 +02:00
2018-04-08 22:45:14 +02:00
hash = hash & 0x7FFFFFFF ; // Make it compatible with unsigned, since negative ID is used for exclusion
2016-08-19 21:48:08 +02:00
}
return hash ;
}
int NetworkedMultiplayerENet : : get_unique_id ( ) const {
2020-02-02 23:34:47 +01:00
ERR_FAIL_COND_V_MSG ( ! active , 0 , " The multiplayer instance isn't currently active. " ) ;
2016-08-19 21:48:08 +02:00
return unique_id ;
}
void NetworkedMultiplayerENet : : set_refuse_new_connections ( bool p_enable ) {
2017-03-05 16:44:50 +01:00
refuse_connections = p_enable ;
2020-07-13 19:14:27 +02:00
# ifdef GODOT_ENET
2020-07-23 10:38:48 +02:00
if ( active ) {
enet_host_refuse_new_connections ( host , p_enable ) ;
}
2020-07-13 19:14:27 +02:00
# endif
2016-08-19 21:48:08 +02:00
}
bool NetworkedMultiplayerENet : : is_refusing_new_connections ( ) const {
return refuse_connections ;
}
2016-08-22 06:14:08 +02:00
void NetworkedMultiplayerENet : : set_compression_mode ( CompressionMode p_mode ) {
2017-03-05 16:44:50 +01:00
compression_mode = p_mode ;
2016-08-22 06:14:08 +02:00
}
2017-03-05 16:44:50 +01:00
NetworkedMultiplayerENet : : CompressionMode NetworkedMultiplayerENet : : get_compression_mode ( ) const {
2016-08-22 06:14:08 +02:00
return compression_mode ;
}
2017-03-05 16:44:50 +01:00
size_t NetworkedMultiplayerENet : : enet_compress ( void * context , const ENetBuffer * inBuffers , size_t inBufferCount , size_t inLimit , enet_uint8 * outData , size_t outLimit ) {
2016-08-22 06:14:08 +02:00
2017-03-05 16:44:50 +01:00
NetworkedMultiplayerENet * enet = ( NetworkedMultiplayerENet * ) ( context ) ;
2016-08-22 06:14:08 +02:00
2017-03-05 16:44:50 +01:00
if ( size_t ( enet - > src_compressor_mem . size ( ) ) < inLimit ) {
enet - > src_compressor_mem . resize ( inLimit ) ;
2016-08-22 06:14:08 +02:00
}
int total = inLimit ;
2017-03-05 16:44:50 +01:00
int ofs = 0 ;
while ( total ) {
for ( size_t i = 0 ; i < inBufferCount ; i + + ) {
int to_copy = MIN ( total , int ( inBuffers [ i ] . dataLength ) ) ;
2021-04-29 12:34:11 +02:00
memcpy ( & enet - > src_compressor_mem . write [ ofs ] , inBuffers [ i ] . data , to_copy ) ;
2017-03-05 16:44:50 +01:00
ofs + = to_copy ;
total - = to_copy ;
2016-08-22 06:14:08 +02:00
}
}
Compression : : Mode mode ;
2017-03-05 16:44:50 +01:00
switch ( enet - > compression_mode ) {
2016-08-22 06:14:08 +02:00
case COMPRESS_FASTLZ : {
2017-03-05 16:44:50 +01:00
mode = Compression : : MODE_FASTLZ ;
2016-08-22 06:14:08 +02:00
} break ;
case COMPRESS_ZLIB : {
2017-03-05 16:44:50 +01:00
mode = Compression : : MODE_DEFLATE ;
2016-08-22 06:14:08 +02:00
} break ;
2017-06-09 03:43:56 +02:00
case COMPRESS_ZSTD : {
mode = Compression : : MODE_ZSTD ;
} break ;
2019-04-09 17:08:36 +02:00
default : {
2020-02-02 23:34:47 +01:00
ERR_FAIL_V_MSG ( 0 , vformat ( " Invalid ENet compression mode: %d " , enet - > compression_mode ) ) ;
2019-04-09 17:08:36 +02:00
}
2016-08-22 06:14:08 +02:00
}
2017-03-05 16:44:50 +01:00
int req_size = Compression : : get_max_compressed_buffer_size ( ofs , mode ) ;
if ( enet - > dst_compressor_mem . size ( ) < req_size ) {
2016-08-22 06:14:08 +02:00
enet - > dst_compressor_mem . resize ( req_size ) ;
}
2017-11-25 04:07:54 +01:00
int ret = Compression : : compress ( enet - > dst_compressor_mem . ptrw ( ) , enet - > src_compressor_mem . ptr ( ) , ofs , mode ) ;
2016-08-22 06:14:08 +02:00
2017-03-05 16:44:50 +01:00
if ( ret < 0 )
2016-08-22 06:14:08 +02:00
return 0 ;
2017-03-05 16:44:50 +01:00
if ( ret > int ( outLimit ) )
2018-04-08 22:45:14 +02:00
return 0 ; // Do not bother
2016-08-22 06:14:08 +02:00
2021-04-29 12:34:11 +02:00
memcpy ( outData , enet - > dst_compressor_mem . ptr ( ) , ret ) ;
2016-08-22 06:14:08 +02:00
return ret ;
}
2017-03-05 16:44:50 +01:00
size_t NetworkedMultiplayerENet : : enet_decompress ( void * context , const enet_uint8 * inData , size_t inLimit , enet_uint8 * outData , size_t outLimit ) {
2016-08-22 06:14:08 +02:00
2017-03-05 16:44:50 +01:00
NetworkedMultiplayerENet * enet = ( NetworkedMultiplayerENet * ) ( context ) ;
2016-08-22 06:14:08 +02:00
int ret = - 1 ;
2017-03-05 16:44:50 +01:00
switch ( enet - > compression_mode ) {
2016-08-22 06:14:08 +02:00
case COMPRESS_FASTLZ : {
2017-03-05 16:44:50 +01:00
ret = Compression : : decompress ( outData , outLimit , inData , inLimit , Compression : : MODE_FASTLZ ) ;
2016-08-22 06:14:08 +02:00
} break ;
case COMPRESS_ZLIB : {
2017-03-05 16:44:50 +01:00
ret = Compression : : decompress ( outData , outLimit , inData , inLimit , Compression : : MODE_DEFLATE ) ;
2016-08-22 06:14:08 +02:00
} break ;
2017-06-09 03:43:56 +02:00
case COMPRESS_ZSTD : {
ret = Compression : : decompress ( outData , outLimit , inData , inLimit , Compression : : MODE_ZSTD ) ;
} break ;
2019-04-09 17:08:36 +02:00
default : {
}
2016-08-22 06:14:08 +02:00
}
2017-03-05 16:44:50 +01:00
if ( ret < 0 ) {
2016-08-22 06:14:08 +02:00
return 0 ;
} else {
return ret ;
}
}
void NetworkedMultiplayerENet : : _setup_compressor ( ) {
2017-03-05 16:44:50 +01:00
switch ( compression_mode ) {
2016-08-22 06:14:08 +02:00
case COMPRESS_NONE : {
2017-03-05 16:44:50 +01:00
enet_host_compress ( host , NULL ) ;
2016-08-22 06:14:08 +02:00
} break ;
case COMPRESS_RANGE_CODER : {
enet_host_compress_with_range_coder ( host ) ;
} break ;
case COMPRESS_FASTLZ :
2017-06-09 03:43:56 +02:00
case COMPRESS_ZLIB :
case COMPRESS_ZSTD : {
2016-08-22 06:14:08 +02:00
2017-03-05 16:44:50 +01:00
enet_host_compress ( host , & enet_compressor ) ;
2016-08-22 06:14:08 +02:00
} break ;
}
}
2017-03-05 16:44:50 +01:00
void NetworkedMultiplayerENet : : enet_compressor_destroy ( void * context ) {
2016-08-22 06:14:08 +02:00
2018-04-10 17:52:10 +02:00
// Nothing to do
}
IP_Address NetworkedMultiplayerENet : : get_peer_address ( int p_peer_id ) const {
2020-02-02 23:34:47 +01:00
ERR_FAIL_COND_V_MSG ( ! peer_map . has ( p_peer_id ) , IP_Address ( ) , vformat ( " Peer ID %d not found in the list of peers. " , p_peer_id ) ) ;
ERR_FAIL_COND_V_MSG ( ! is_server ( ) & & p_peer_id ! = 1 , IP_Address ( ) , " Can't get the address of peers other than the server (ID -1) when acting as a client. " ) ;
ERR_FAIL_COND_V_MSG ( peer_map [ p_peer_id ] = = NULL , IP_Address ( ) , vformat ( " Peer ID %d found in the list of peers, but is null. " , p_peer_id ) ) ;
2018-04-10 17:52:10 +02:00
IP_Address out ;
# ifdef GODOT_ENET
out . set_ipv6 ( ( uint8_t * ) & ( peer_map [ p_peer_id ] - > address . host ) ) ;
# else
out . set_ipv4 ( ( uint8_t * ) & ( peer_map [ p_peer_id ] - > address . host ) ) ;
# endif
return out ;
}
int NetworkedMultiplayerENet : : get_peer_port ( int p_peer_id ) const {
2020-02-02 23:34:47 +01:00
ERR_FAIL_COND_V_MSG ( ! peer_map . has ( p_peer_id ) , 0 , vformat ( " Peer ID %d not found in the list of peers. " , p_peer_id ) ) ;
ERR_FAIL_COND_V_MSG ( ! is_server ( ) & & p_peer_id ! = 1 , 0 , " Can't get the address of peers other than the server (ID -1) when acting as a client. " ) ;
ERR_FAIL_COND_V_MSG ( peer_map [ p_peer_id ] = = NULL , 0 , vformat ( " Peer ID %d found in the list of peers, but is null. " , p_peer_id ) ) ;
2018-04-10 17:52:10 +02:00
# ifdef GODOT_ENET
return peer_map [ p_peer_id ] - > address . port ;
# else
return peer_map [ p_peer_id ] - > address . port ;
# endif
2016-08-22 06:14:08 +02:00
}
2020-01-20 07:43:12 +01:00
void NetworkedMultiplayerENet : : set_peer_timeout ( int p_peer_id , int p_timeout_limit , int p_timeout_min , int p_timeout_max ) {
ERR_FAIL_COND_MSG ( ! peer_map . has ( p_peer_id ) , vformat ( " Peer ID %d not found in the list of peers. " , p_peer_id ) ) ;
ERR_FAIL_COND_MSG ( ! is_server ( ) & & p_peer_id ! = 1 , " Can't change the timeout of peers other then the server when acting as a client. " ) ;
ERR_FAIL_COND_MSG ( peer_map [ p_peer_id ] = = nullptr , vformat ( " Peer ID %d found in the list of peers, but is null. " , p_peer_id ) ) ;
ERR_FAIL_COND_MSG ( p_timeout_limit > p_timeout_min | | p_timeout_min > p_timeout_max , " Timeout limit must be less than minimum timeout, which itself must be less then maximum timeout " ) ;
enet_peer_timeout ( peer_map [ p_peer_id ] , p_timeout_limit , p_timeout_min , p_timeout_max ) ;
}
2018-05-12 19:42:00 +02:00
void NetworkedMultiplayerENet : : set_transfer_channel ( int p_channel ) {
2020-02-02 23:34:47 +01:00
ERR_FAIL_COND_MSG ( p_channel < - 1 | | p_channel > = channel_count , vformat ( " The transfer channel must be set between 0 and %d, inclusive (got %d). " , channel_count - 1 , p_channel ) ) ;
ERR_FAIL_COND_MSG ( p_channel = = SYSCH_CONFIG , vformat ( " The channel %d is reserved. " , SYSCH_CONFIG ) ) ;
2018-05-12 19:42:00 +02:00
transfer_channel = p_channel ;
}
int NetworkedMultiplayerENet : : get_transfer_channel ( ) const {
return transfer_channel ;
}
void NetworkedMultiplayerENet : : set_channel_count ( int p_channel ) {
2020-02-02 23:34:47 +01:00
ERR_FAIL_COND_MSG ( active , " The channel count can't be set while the multiplayer instance is active. " ) ;
ERR_FAIL_COND_MSG ( p_channel < SYSCH_MAX , vformat ( " The channel count must be greater than or equal to %d to account for reserved channels (got %d). " , SYSCH_MAX , p_channel ) ) ;
2018-05-12 19:42:00 +02:00
channel_count = p_channel ;
}
int NetworkedMultiplayerENet : : get_channel_count ( ) const {
return channel_count ;
}
void NetworkedMultiplayerENet : : set_always_ordered ( bool p_ordered ) {
always_ordered = p_ordered ;
}
bool NetworkedMultiplayerENet : : is_always_ordered ( ) const {
return always_ordered ;
}
2019-11-26 17:21:19 +01:00
void NetworkedMultiplayerENet : : set_server_relay_enabled ( bool p_enabled ) {
2020-02-02 23:34:47 +01:00
ERR_FAIL_COND_MSG ( active , " Server relaying can't be toggled while the multiplayer instance is active. " ) ;
2019-11-26 17:21:19 +01:00
server_relay = p_enabled ;
}
bool NetworkedMultiplayerENet : : is_server_relay_enabled ( ) const {
return server_relay ;
}
2016-08-14 19:06:51 +02:00
void NetworkedMultiplayerENet : : _bind_methods ( ) {
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " create_server " , " port " , " max_clients " , " in_bandwidth " , " out_bandwidth " ) , & NetworkedMultiplayerENet : : create_server , DEFVAL ( 32 ) , DEFVAL ( 0 ) , DEFVAL ( 0 ) ) ;
2018-05-07 00:28:59 +02:00
ClassDB : : bind_method ( D_METHOD ( " create_client " , " address " , " port " , " in_bandwidth " , " out_bandwidth " , " client_port " ) , & NetworkedMultiplayerENet : : create_client , DEFVAL ( 0 ) , DEFVAL ( 0 ) , DEFVAL ( 0 ) ) ;
ClassDB : : bind_method ( D_METHOD ( " close_connection " , " wait_usec " ) , & NetworkedMultiplayerENet : : close_connection , DEFVAL ( 100 ) ) ;
2018-04-08 22:45:14 +02:00
ClassDB : : bind_method ( D_METHOD ( " disconnect_peer " , " id " , " now " ) , & NetworkedMultiplayerENet : : disconnect_peer , DEFVAL ( false ) ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_compression_mode " , " mode " ) , & NetworkedMultiplayerENet : : set_compression_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " get_compression_mode " ) , & NetworkedMultiplayerENet : : get_compression_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " set_bind_ip " , " ip " ) , & NetworkedMultiplayerENet : : set_bind_ip ) ;
2020-01-13 16:51:17 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_dtls_enabled " , " enabled " ) , & NetworkedMultiplayerENet : : set_dtls_enabled ) ;
ClassDB : : bind_method ( D_METHOD ( " is_dtls_enabled " ) , & NetworkedMultiplayerENet : : is_dtls_enabled ) ;
ClassDB : : bind_method ( D_METHOD ( " set_dtls_key " , " key " ) , & NetworkedMultiplayerENet : : set_dtls_key ) ;
ClassDB : : bind_method ( D_METHOD ( " set_dtls_certificate " , " certificate " ) , & NetworkedMultiplayerENet : : set_dtls_certificate ) ;
ClassDB : : bind_method ( D_METHOD ( " set_dtls_verify_enabled " , " enabled " ) , & NetworkedMultiplayerENet : : set_dtls_verify_enabled ) ;
ClassDB : : bind_method ( D_METHOD ( " is_dtls_verify_enabled " ) , & NetworkedMultiplayerENet : : is_dtls_verify_enabled ) ;
2018-05-08 14:40:08 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_peer_address " , " id " ) , & NetworkedMultiplayerENet : : get_peer_address ) ;
ClassDB : : bind_method ( D_METHOD ( " get_peer_port " , " id " ) , & NetworkedMultiplayerENet : : get_peer_port ) ;
2020-01-20 07:43:12 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_peer_timeout " , " id " , " timeout_limit " , " timeout_min " , " timeout_max " ) , & NetworkedMultiplayerENet : : set_peer_timeout ) ;
2017-03-05 16:44:50 +01:00
2018-05-12 19:42:00 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_packet_channel " ) , & NetworkedMultiplayerENet : : get_packet_channel ) ;
ClassDB : : bind_method ( D_METHOD ( " get_last_packet_channel " ) , & NetworkedMultiplayerENet : : get_last_packet_channel ) ;
ClassDB : : bind_method ( D_METHOD ( " set_transfer_channel " , " channel " ) , & NetworkedMultiplayerENet : : set_transfer_channel ) ;
ClassDB : : bind_method ( D_METHOD ( " get_transfer_channel " ) , & NetworkedMultiplayerENet : : get_transfer_channel ) ;
ClassDB : : bind_method ( D_METHOD ( " set_channel_count " , " channels " ) , & NetworkedMultiplayerENet : : set_channel_count ) ;
ClassDB : : bind_method ( D_METHOD ( " get_channel_count " ) , & NetworkedMultiplayerENet : : get_channel_count ) ;
ClassDB : : bind_method ( D_METHOD ( " set_always_ordered " , " ordered " ) , & NetworkedMultiplayerENet : : set_always_ordered ) ;
ClassDB : : bind_method ( D_METHOD ( " is_always_ordered " ) , & NetworkedMultiplayerENet : : is_always_ordered ) ;
2019-11-26 17:21:19 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_server_relay_enabled " , " enabled " ) , & NetworkedMultiplayerENet : : set_server_relay_enabled ) ;
ClassDB : : bind_method ( D_METHOD ( " is_server_relay_enabled " ) , & NetworkedMultiplayerENet : : is_server_relay_enabled ) ;
2018-05-12 19:42:00 +02:00
2018-01-11 23:35:12 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " compression_mode " , PROPERTY_HINT_ENUM , " None,Range Coder,FastLZ,ZLib,ZStd " ) , " set_compression_mode " , " get_compression_mode " ) ;
2018-05-12 19:42:00 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " transfer_channel " ) , " set_transfer_channel " , " get_transfer_channel " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " channel_count " ) , " set_channel_count " , " get_channel_count " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " always_ordered " ) , " set_always_ordered " , " is_always_ordered " ) ;
2019-11-26 17:21:19 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " server_relay " ) , " set_server_relay_enabled " , " is_server_relay_enabled " ) ;
2020-01-13 16:51:17 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " dtls_verify " ) , " set_dtls_verify_enabled " , " is_dtls_verify_enabled " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " use_dtls " ) , " set_dtls_enabled " , " is_dtls_enabled " ) ;
2018-01-11 23:35:12 +01:00
2017-08-20 17:45:01 +02:00
BIND_ENUM_CONSTANT ( COMPRESS_NONE ) ;
BIND_ENUM_CONSTANT ( COMPRESS_RANGE_CODER ) ;
BIND_ENUM_CONSTANT ( COMPRESS_FASTLZ ) ;
BIND_ENUM_CONSTANT ( COMPRESS_ZLIB ) ;
BIND_ENUM_CONSTANT ( COMPRESS_ZSTD ) ;
2016-08-14 19:06:51 +02:00
}
2017-03-05 16:44:50 +01:00
NetworkedMultiplayerENet : : NetworkedMultiplayerENet ( ) {
active = false ;
server = false ;
refuse_connections = false ;
2019-11-26 17:21:19 +01:00
server_relay = true ;
2017-03-05 16:44:50 +01:00
unique_id = 0 ;
target_peer = 0 ;
current_packet . packet = NULL ;
transfer_mode = TRANSFER_MODE_RELIABLE ;
2018-05-12 19:42:00 +02:00
channel_count = SYSCH_MAX ;
transfer_channel = - 1 ;
always_ordered = false ;
2017-03-05 16:44:50 +01:00
connection_status = CONNECTION_DISCONNECTED ;
compression_mode = COMPRESS_NONE ;
enet_compressor . context = this ;
enet_compressor . compress = enet_compress ;
enet_compressor . decompress = enet_decompress ;
enet_compressor . destroy = enet_compressor_destroy ;
2017-01-22 06:00:59 +01:00
bind_ip = IP_Address ( " * " ) ;
2020-01-13 16:51:17 +01:00
dtls_enabled = false ;
dtls_verify = true ;
2016-08-14 18:29:25 +02:00
}
2016-08-14 19:06:51 +02:00
2017-03-05 16:44:50 +01:00
NetworkedMultiplayerENet : : ~ NetworkedMultiplayerENet ( ) {
2016-08-14 18:29:25 +02:00
2019-06-01 15:42:22 +02:00
if ( active ) {
close_connection ( ) ;
}
2016-08-14 18:29:25 +02:00
}
2016-08-27 13:41:34 +02:00
2018-05-07 00:28:59 +02:00
// Sets IP for ENet to bind when using create_server or create_client
2016-08-27 13:41:34 +02:00
// if no IP is set, then ENet bind to ENET_HOST_ANY
2017-03-05 16:44:50 +01:00
void NetworkedMultiplayerENet : : set_bind_ip ( const IP_Address & p_ip ) {
2020-02-02 23:34:47 +01:00
ERR_FAIL_COND_MSG ( ! p_ip . is_valid ( ) & & ! p_ip . is_wildcard ( ) , vformat ( " Invalid bind IP address: %s " , String ( p_ip ) ) ) ;
2017-01-22 06:00:59 +01:00
bind_ip = p_ip ;
2016-08-27 13:41:34 +02:00
}
2020-01-13 16:51:17 +01:00
void NetworkedMultiplayerENet : : set_dtls_enabled ( bool p_enabled ) {
ERR_FAIL_COND ( active ) ;
dtls_enabled = p_enabled ;
}
bool NetworkedMultiplayerENet : : is_dtls_enabled ( ) const {
return dtls_enabled ;
}
void NetworkedMultiplayerENet : : set_dtls_verify_enabled ( bool p_enabled ) {
ERR_FAIL_COND ( active ) ;
dtls_verify = p_enabled ;
}
bool NetworkedMultiplayerENet : : is_dtls_verify_enabled ( ) const {
return dtls_verify ;
}
void NetworkedMultiplayerENet : : set_dtls_key ( Ref < CryptoKey > p_key ) {
ERR_FAIL_COND ( active ) ;
dtls_key = p_key ;
}
void NetworkedMultiplayerENet : : set_dtls_certificate ( Ref < X509Certificate > p_cert ) {
ERR_FAIL_COND ( active ) ;
dtls_cert = p_cert ;
}