diff options
author | Fabio Alessandrelli <fabio.alessandrelli@gmail.com> | 2022-10-22 17:49:40 +0200 |
---|---|---|
committer | Fabio Alessandrelli <fabio.alessandrelli@gmail.com> | 2022-10-28 21:18:01 +0200 |
commit | 39f3d9d59e80d5a9f62925abca596d87ce1e4d0f (patch) | |
tree | e958ee207578ecf5912210377db44496faa5cc6f | |
parent | 028db9f2b5b6d2ca9a00d3b08c17f82b5298e149 (diff) |
[MP] Add MultiplayerPeer disconnect_peer, close.
Update ENet, WebRTC, and WebSocket to support peer disconnection and
unify the close function.
-rw-r--r-- | doc/classes/MultiplayerPeer.xml | 16 | ||||
-rw-r--r-- | doc/classes/MultiplayerPeerExtension.xml | 14 | ||||
-rw-r--r-- | modules/enet/doc_classes/ENetMultiplayerPeer.xml | 11 | ||||
-rw-r--r-- | modules/enet/enet_multiplayer_peer.cpp | 247 | ||||
-rw-r--r-- | modules/enet/enet_multiplayer_peer.h | 11 | ||||
-rw-r--r-- | modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml | 6 | ||||
-rw-r--r-- | modules/webrtc/webrtc_multiplayer_peer.cpp | 13 | ||||
-rw-r--r-- | modules/webrtc/webrtc_multiplayer_peer.h | 29 | ||||
-rw-r--r-- | modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml | 16 | ||||
-rw-r--r-- | modules/websocket/websocket_multiplayer_peer.cpp | 12 | ||||
-rw-r--r-- | modules/websocket/websocket_multiplayer_peer.h | 5 | ||||
-rw-r--r-- | scene/main/multiplayer_peer.cpp | 4 | ||||
-rw-r--r-- | scene/main/multiplayer_peer.h | 5 |
13 files changed, 188 insertions, 201 deletions
diff --git a/doc/classes/MultiplayerPeer.xml b/doc/classes/MultiplayerPeer.xml index ba6c60a088..6661fbfe0b 100644 --- a/doc/classes/MultiplayerPeer.xml +++ b/doc/classes/MultiplayerPeer.xml @@ -13,6 +13,20 @@ <link title="WebRTC Signaling Demo">https://godotengine.org/asset-library/asset/537</link> </tutorials> <methods> + <method name="close"> + <return type="void" /> + <description> + Immediately close the multiplayer peer returning to the state [constant CONNECTION_DISCONNECTED]. Connected peers will be dropped without emitting [signal peer_disconnected]. + </description> + </method> + <method name="disconnect_peer"> + <return type="void" /> + <param index="0" name="peer" type="int" /> + <param index="1" name="force" type="bool" default="false" /> + <description> + Disconnects the given [param peer] from this host. If [param force] is [code]true[/code] the [signal peer_disconnected] signal will not be emitted for this peer. + </description> + </method> <method name="generate_unique_id" qualifiers="const"> <return type="int" /> <description> @@ -79,7 +93,7 @@ [b]Note:[/b] The default channel ([code]0[/code]) actually works as 3 separate channels (one for each [enum TransferMode]) so that [constant TRANSFER_MODE_RELIABLE] and [constant TRANSFER_MODE_UNRELIABLE_ORDERED] does not interact with each other by default. Refer to the specific network API documentation (e.g. ENet or WebRTC) to learn how to set up channels correctly. </member> <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" enum="MultiplayerPeer.TransferMode" default="2"> - The manner in which to send packets to the [code]target_peer[/code]. See [enum TransferMode]. + The manner in which to send packets to the target peer. See [enum TransferMode], and the [method set_target_peer] method. </member> </members> <signals> diff --git a/doc/classes/MultiplayerPeerExtension.xml b/doc/classes/MultiplayerPeerExtension.xml index 18bc18e6e7..5717135b80 100644 --- a/doc/classes/MultiplayerPeerExtension.xml +++ b/doc/classes/MultiplayerPeerExtension.xml @@ -9,6 +9,20 @@ <tutorials> </tutorials> <methods> + <method name="_close" qualifiers="virtual"> + <return type="void" /> + <description> + Called when the multiplayer peer should be immediately closed (see [method MultiplayerPeer.close]). + </description> + </method> + <method name="_disconnect_peer" qualifiers="virtual"> + <return type="void" /> + <param index="0" name="p_peer" type="int" /> + <param index="1" name="p_force" type="bool" /> + <description> + Called when the connected [param p_peer] should be forcibly disconnected (see [method MultiplayerPeer.disconnect_peer]). + </description> + </method> <method name="_get_available_packet_count" qualifiers="virtual const"> <return type="int" /> <description> diff --git a/modules/enet/doc_classes/ENetMultiplayerPeer.xml b/modules/enet/doc_classes/ENetMultiplayerPeer.xml index f02fc893fd..2e0d1f5079 100644 --- a/modules/enet/doc_classes/ENetMultiplayerPeer.xml +++ b/modules/enet/doc_classes/ENetMultiplayerPeer.xml @@ -21,13 +21,6 @@ [b]Note:[/b] The [code]host[/code] must have exactly one peer in the [constant ENetPacketPeer.STATE_CONNECTED] state. </description> </method> - <method name="close_connection"> - <return type="void" /> - <param index="0" name="wait_usec" type="int" default="100" /> - <description> - Closes the connection. Ignored if no connection is currently established. If this is a server it tries to notify all clients before forcibly disconnecting them. If this is a client it simply closes the connection to the server. - </description> - </method> <method name="create_client"> <return type="int" enum="Error" /> <param index="0" name="address" type="String" /> @@ -37,7 +30,7 @@ <param index="4" name="out_bandwidth" type="int" default="0" /> <param index="5" name="local_port" type="int" default="0" /> <description> - Create client that connects to a server at [code]address[/code] using specified [code]port[/code]. The given address needs to be either a fully qualified domain name (e.g. [code]"www.example.com"[/code]) or an IP address in IPv4 or IPv6 format (e.g. [code]"192.168.1.1"[/code]). The [code]port[/code] is the port the server is listening on. The [code]channel_count[/code] parameter can be used to specify the number of ENet channels allocated for the connection. The [code]in_bandwidth[/code] and [code]out_bandwidth[/code] parameters can be used to limit the incoming and outgoing bandwidth to the given number of bytes per second. The default of 0 means unlimited bandwidth. Note that ENet will strategically drop packets on specific sides of a connection between peers to ensure the peer's bandwidth is not overwhelmed. The bandwidth parameters also determine the window size of a connection which limits the amount of reliable packets that may be in transit at any given time. Returns [constant OK] if a client was created, [constant ERR_ALREADY_IN_USE] if this ENetMultiplayerPeer instance already has an open connection (in which case you need to call [method close_connection] first) or [constant ERR_CANT_CREATE] if the client could not be created. If [code]local_port[/code] is specified, the client will also listen to the given port; this is useful for some NAT traversal techniques. + Create client that connects to a server at [code]address[/code] using specified [code]port[/code]. The given address needs to be either a fully qualified domain name (e.g. [code]"www.example.com"[/code]) or an IP address in IPv4 or IPv6 format (e.g. [code]"192.168.1.1"[/code]). The [code]port[/code] is the port the server is listening on. The [code]channel_count[/code] parameter can be used to specify the number of ENet channels allocated for the connection. The [code]in_bandwidth[/code] and [code]out_bandwidth[/code] parameters can be used to limit the incoming and outgoing bandwidth to the given number of bytes per second. The default of 0 means unlimited bandwidth. Note that ENet will strategically drop packets on specific sides of a connection between peers to ensure the peer's bandwidth is not overwhelmed. The bandwidth parameters also determine the window size of a connection which limits the amount of reliable packets that may be in transit at any given time. Returns [constant OK] if a client was created, [constant ERR_ALREADY_IN_USE] if this ENetMultiplayerPeer instance already has an open connection (in which case you need to call [method MultiplayerPeer.close] first) or [constant ERR_CANT_CREATE] if the client could not be created. If [code]local_port[/code] is specified, the client will also listen to the given port; this is useful for some NAT traversal techniques. </description> </method> <method name="create_mesh"> @@ -55,7 +48,7 @@ <param index="3" name="in_bandwidth" type="int" default="0" /> <param index="4" name="out_bandwidth" type="int" default="0" /> <description> - Create server that listens to connections via [code]port[/code]. The port needs to be an available, unused port between 0 and 65535. Note that ports below 1024 are privileged and may require elevated permissions depending on the platform. To change the interface the server listens on, use [method set_bind_ip]. The default IP is the wildcard [code]"*"[/code], which listens on all available interfaces. [code]max_clients[/code] is the maximum number of clients that are allowed at once, any number up to 4095 may be used, although the achievable number of simultaneous clients may be far lower and depends on the application. For additional details on the bandwidth parameters, see [method create_client]. Returns [constant OK] if a server was created, [constant ERR_ALREADY_IN_USE] if this ENetMultiplayerPeer instance already has an open connection (in which case you need to call [method close_connection] first) or [constant ERR_CANT_CREATE] if the server could not be created. + Create server that listens to connections via [code]port[/code]. The port needs to be an available, unused port between 0 and 65535. Note that ports below 1024 are privileged and may require elevated permissions depending on the platform. To change the interface the server listens on, use [method set_bind_ip]. The default IP is the wildcard [code]"*"[/code], which listens on all available interfaces. [code]max_clients[/code] is the maximum number of clients that are allowed at once, any number up to 4095 may be used, although the achievable number of simultaneous clients may be far lower and depends on the application. For additional details on the bandwidth parameters, see [method create_client]. Returns [constant OK] if a server was created, [constant ERR_ALREADY_IN_USE] if this ENetMultiplayerPeer instance already has an open connection (in which case you need to call [method MultiplayerPeer.close] first) or [constant ERR_CANT_CREATE] if the server could not be created. </description> </method> <method name="get_peer" qualifiers="const"> diff --git a/modules/enet/enet_multiplayer_peer.cpp b/modules/enet/enet_multiplayer_peer.cpp index c93db3b972..31ae643b59 100644 --- a/modules/enet/enet_multiplayer_peer.cpp +++ b/modules/enet/enet_multiplayer_peer.cpp @@ -146,92 +146,24 @@ void ENetMultiplayerPeer::_store_packet(int32_t p_source, ENetConnection::Event incoming_packets.push_back(packet); } -bool ENetMultiplayerPeer::_parse_server_event(ENetConnection::EventType p_type, ENetConnection::Event &p_event) { - switch (p_type) { - case ENetConnection::EVENT_CONNECT: { - if (is_refusing_new_connections()) { - p_event.peer->reset(); - return false; - } - // Client joined with invalid ID, probably trying to exploit us. - if (p_event.data < 2 || peers.has((int)p_event.data)) { - p_event.peer->reset(); - return false; - } - int id = p_event.data; - p_event.peer->set_meta(SNAME("_net_id"), id); - peers[id] = p_event.peer; - - emit_signal(SNAME("peer_connected"), id); - return false; - } - case ENetConnection::EVENT_DISCONNECT: { - int id = p_event.peer->get_meta(SNAME("_net_id")); - if (!peers.has(id)) { - // Never fully connected. - return false; - } - - emit_signal(SNAME("peer_disconnected"), id); - peers.erase(id); - return false; - } - case ENetConnection::EVENT_RECEIVE: { - int32_t source = p_event.peer->get_meta(SNAME("_net_id")); - _store_packet(source, p_event); - return false; +void ENetMultiplayerPeer::_disconnect_inactive_peers() { + HashSet<int> to_drop; + for (const KeyValue<int, Ref<ENetPacketPeer>> &E : peers) { + if (E.value->is_active()) { + continue; } - default: - return true; + to_drop.insert(E.key); } -} - -bool ENetMultiplayerPeer::_parse_client_event(ENetConnection::EventType p_type, ENetConnection::Event &p_event) { - switch (p_type) { - case ENetConnection::EVENT_CONNECT: { - connection_status = CONNECTION_CONNECTED; - emit_signal(SNAME("peer_connected"), 1); - emit_signal(SNAME("connection_succeeded")); - return false; + for (const int &P : to_drop) { + peers.erase(P); + if (hosts.has(P)) { + hosts.erase(P); } - case ENetConnection::EVENT_DISCONNECT: { - if (connection_status == CONNECTION_CONNECTED) { - // Client just disconnected from server. - emit_signal(SNAME("server_disconnected")); - } else { - emit_signal(SNAME("connection_failed")); - } - close_connection(); - return true; + if (active_mode == MODE_CLIENT) { + ERR_CONTINUE(P != TARGET_PEER_SERVER); + emit_signal(SNAME("server_disconnected")); } - case ENetConnection::EVENT_RECEIVE: { - _store_packet(1, p_event); - return false; - } - default: - return true; - } -} - -bool ENetMultiplayerPeer::_parse_mesh_event(ENetConnection::EventType p_type, ENetConnection::Event &p_event, int p_peer_id) { - switch (p_type) { - case ENetConnection::EVENT_CONNECT: - p_event.peer->reset(); - return false; - case ENetConnection::EVENT_DISCONNECT: - if (peers.has(p_peer_id)) { - emit_signal(SNAME("peer_disconnected"), p_peer_id); - peers.erase(p_peer_id); - } - hosts.erase(p_peer_id); - return true; - case ENetConnection::EVENT_RECEIVE: { - _store_packet(p_peer_id, p_event); - return false; - } break; - default: - // Nothing to do - return true; + emit_signal(SNAME("peer_disconnected"), P); } } @@ -240,74 +172,96 @@ void ENetMultiplayerPeer::poll() { _pop_current_packet(); + _disconnect_inactive_peers(); + switch (active_mode) { case MODE_CLIENT: { - if (peers.has(1) && !peers[1]->is_active()) { - if (connection_status == CONNECTION_CONNECTED) { - // Client just disconnected from server. - emit_signal(SNAME("server_disconnected")); - } else { - emit_signal(SNAME("connection_failed")); - } - close_connection(); + if (!peers.has(1)) { + close(); return; } ENetConnection::Event event; ENetConnection::EventType ret = hosts[0]->service(0, event); - if (ret == ENetConnection::EVENT_ERROR) { - return; - } do { - if (_parse_client_event(ret, event)) { - return; + if (ret == ENetConnection::EVENT_CONNECT) { + connection_status = CONNECTION_CONNECTED; + emit_signal(SNAME("peer_connected"), 1); + emit_signal(SNAME("connection_succeeded")); + } else if (ret == ENetConnection::EVENT_DISCONNECT) { + if (connection_status == CONNECTION_CONNECTED) { + // Client just disconnected from server. + emit_signal(SNAME("server_disconnected")); + emit_signal(SNAME("peer_disconnected"), 1); + } else { + emit_signal(SNAME("connection_failed")); + } + close(); + } else if (ret == ENetConnection::EVENT_RECEIVE) { + _store_packet(1, event); + } else if (ret != ENetConnection::EVENT_NONE) { + close(); // Error. } - } while (hosts[0]->check_events(ret, event) > 0); + } while (hosts.has(0) && hosts[0]->check_events(ret, event) > 0); } break; case MODE_SERVER: { - for (const KeyValue<int, Ref<ENetPacketPeer>> &E : peers) { - if (!(E.value->is_active())) { - emit_signal(SNAME("peer_disconnected"), E.value->get_meta(SNAME("_net_id"))); - peers.erase(E.key); - } - } ENetConnection::Event event; ENetConnection::EventType ret = hosts[0]->service(0, event); - if (ret == ENetConnection::EVENT_ERROR) { - return; - } do { - if (_parse_server_event(ret, event)) { - return; + if (ret == ENetConnection::EVENT_CONNECT) { + if (is_refusing_new_connections()) { + event.peer->reset(); + continue; + } + // Client joined with invalid ID, probably trying to exploit us. + if (event.data < 2 || peers.has((int)event.data)) { + event.peer->reset(); + continue; + } + int id = event.data; + event.peer->set_meta(SNAME("_net_id"), id); + peers[id] = event.peer; + emit_signal(SNAME("peer_connected"), id); + } else if (ret == ENetConnection::EVENT_DISCONNECT) { + int id = event.peer->get_meta(SNAME("_net_id")); + if (!peers.has(id)) { + // Never fully connected. + continue; + } + emit_signal(SNAME("peer_disconnected"), id); + peers.erase(id); + } else if (ret == ENetConnection::EVENT_RECEIVE) { + int32_t source = event.peer->get_meta(SNAME("_net_id")); + _store_packet(source, event); + } else if (ret != ENetConnection::EVENT_NONE) { + close(); // Error } - } while (hosts[0]->check_events(ret, event) > 0); + } while (hosts.has(0) && hosts[0]->check_events(ret, event) > 0); } break; case MODE_MESH: { - for (const KeyValue<int, Ref<ENetPacketPeer>> &E : peers) { - if (!(E.value->is_active())) { - emit_signal(SNAME("peer_disconnected"), E.key); - peers.erase(E.key); - if (hosts.has(E.key)) { - hosts.erase(E.key); - } - } - } + HashSet<int> to_drop; for (KeyValue<int, Ref<ENetConnection>> &E : hosts) { ENetConnection::Event event; ENetConnection::EventType ret = E.value->service(0, event); - if (ret == ENetConnection::EVENT_ERROR) { - if (peers.has(E.key)) { - emit_signal(SNAME("peer_disconnected"), E.key); - peers.erase(E.key); - } - hosts.erase(E.key); - continue; - } do { - if (_parse_mesh_event(ret, event, E.key)) { + if (ret == ENetConnection::EVENT_CONNECT) { + event.peer->reset(); + } else if (ret == ENetConnection::EVENT_RECEIVE) { + _store_packet(E.key, event); + } else if (ret == ENetConnection::EVENT_NONE) { + break; // Keep polling the others. + } else { + to_drop.insert(E.key); // Error or disconnect. break; // Keep polling the others. } } while (E.value->check_events(ret, event) > 0); } + for (const int &P : to_drop) { + if (peers.has(P)) { + emit_signal(SNAME("peer_disconnected"), P); + peers.erase(P); + } + hosts.erase(P); + } } break; default: return; @@ -322,29 +276,41 @@ bool ENetMultiplayerPeer::is_server_relay_supported() const { return active_mode == MODE_SERVER || active_mode == MODE_CLIENT; } -void ENetMultiplayerPeer::close_connection(uint32_t wait_usec) { +void ENetMultiplayerPeer::disconnect_peer(int p_peer, bool p_force) { + ERR_FAIL_COND(!_is_active() || !peers.has(p_peer)); + peers[p_peer]->peer_disconnect(0); // Will be removed during next poll. + if (active_mode == MODE_CLIENT || active_mode == MODE_SERVER) { + hosts[0]->flush(); + } else { + ERR_FAIL_COND(!hosts.has(p_peer)); + hosts[p_peer]->flush(); + } + if (p_force) { + peers.erase(p_peer); + if (hosts.has(p_peer)) { + hosts.erase(p_peer); + } + if (active_mode == MODE_CLIENT) { + hosts.clear(); // Avoid flushing again. + close(); + } + } +} + +void ENetMultiplayerPeer::close() { if (!_is_active()) { return; } _pop_current_packet(); - bool peers_disconnected = false; for (KeyValue<int, Ref<ENetPacketPeer>> &E : peers) { if (E.value.is_valid() && E.value->get_state() == ENetPacketPeer::STATE_CONNECTED) { - E.value->peer_disconnect_now(unique_id); - peers_disconnected = true; + E.value->peer_disconnect_now(0); } } - - if (peers_disconnected) { - for (KeyValue<int, Ref<ENetConnection>> &E : hosts) { - E.value->flush(); - } - - if (wait_usec > 0) { - OS::get_singleton()->delay_usec(wait_usec); // Wait for disconnection packets to send - } + for (KeyValue<int, Ref<ENetConnection>> &E : hosts) { + E.value->flush(); } active_mode = MODE_NONE; @@ -516,7 +482,6 @@ void ENetMultiplayerPeer::_bind_methods() { ClassDB::bind_method(D_METHOD("create_client", "address", "port", "channel_count", "in_bandwidth", "out_bandwidth", "local_port"), &ENetMultiplayerPeer::create_client, DEFVAL(0), DEFVAL(0), DEFVAL(0), DEFVAL(0)); ClassDB::bind_method(D_METHOD("create_mesh", "unique_id"), &ENetMultiplayerPeer::create_mesh); ClassDB::bind_method(D_METHOD("add_mesh_peer", "peer_id", "host"), &ENetMultiplayerPeer::add_mesh_peer); - ClassDB::bind_method(D_METHOD("close_connection", "wait_usec"), &ENetMultiplayerPeer::close_connection, DEFVAL(100)); ClassDB::bind_method(D_METHOD("set_bind_ip", "ip"), &ENetMultiplayerPeer::set_bind_ip); ClassDB::bind_method(D_METHOD("get_host"), &ENetMultiplayerPeer::get_host); @@ -531,7 +496,7 @@ ENetMultiplayerPeer::ENetMultiplayerPeer() { ENetMultiplayerPeer::~ENetMultiplayerPeer() { if (_is_active()) { - close_connection(); + close(); } } diff --git a/modules/enet/enet_multiplayer_peer.h b/modules/enet/enet_multiplayer_peer.h index 85692e8eee..2665b69669 100644 --- a/modules/enet/enet_multiplayer_peer.h +++ b/modules/enet/enet_multiplayer_peer.h @@ -83,9 +83,7 @@ private: void _store_packet(int32_t p_source, ENetConnection::Event &p_event); void _pop_current_packet(); - bool _parse_server_event(ENetConnection::EventType p_event_type, ENetConnection::Event &p_event); - bool _parse_client_event(ENetConnection::EventType p_event_type, ENetConnection::Event &p_event); - bool _parse_mesh_event(ENetConnection::EventType p_event_type, ENetConnection::Event &p_event, int p_peer_id); + void _disconnect_inactive_peers(); void _destroy_unused(ENetPacket *p_packet); _FORCE_INLINE_ bool _is_active() const { return active_mode != MODE_NONE; } @@ -102,6 +100,9 @@ public: virtual int get_packet_channel() const override; virtual void poll() override; + virtual void close() override; + virtual void disconnect_peer(int p_peer, bool p_force = false) override; + virtual bool is_server() const override; virtual bool is_server_relay_supported() const override; @@ -122,10 +123,6 @@ public: Error create_mesh(int p_id); Error add_mesh_peer(int p_id, Ref<ENetConnection> p_host); - void close_connection(uint32_t wait_usec = 100); - - void disconnect_peer(int p_peer, bool now = false); - void set_bind_ip(const IPAddress &p_ip); Ref<ENetConnection> get_host() const; diff --git a/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml index 0b42c6ed35..91ee65e9bd 100644 --- a/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml +++ b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml @@ -22,12 +22,6 @@ Three channels will be created for reliable, unreliable, and ordered transport. The value of [code]unreliable_lifetime[/code] will be passed to the [code]maxPacketLifetime[/code] option when creating unreliable and ordered channels (see [method WebRTCPeerConnection.create_data_channel]). </description> </method> - <method name="close"> - <return type="void" /> - <description> - 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" /> diff --git a/modules/webrtc/webrtc_multiplayer_peer.cpp b/modules/webrtc/webrtc_multiplayer_peer.cpp index 5ea81d5a1b..163b17fa6f 100644 --- a/modules/webrtc/webrtc_multiplayer_peer.cpp +++ b/modules/webrtc/webrtc_multiplayer_peer.cpp @@ -42,7 +42,6 @@ void WebRTCMultiplayerPeer::_bind_methods() { 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); - ClassDB::bind_method(D_METHOD("close"), &WebRTCMultiplayerPeer::close); } void WebRTCMultiplayerPeer::set_target_peer(int p_peer_id) { @@ -352,6 +351,18 @@ void WebRTCMultiplayerPeer::remove_peer(int p_peer_id) { } } +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. + } +} + Error WebRTCMultiplayerPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { // Peer not available if (next_packet_peer == 0 || !peer_map.has(next_packet_peer)) { diff --git a/modules/webrtc/webrtc_multiplayer_peer.h b/modules/webrtc/webrtc_multiplayer_peer.h index 3f608200fd..0556ef029c 100644 --- a/modules/webrtc/webrtc_multiplayer_peer.h +++ b/modules/webrtc/webrtc_multiplayer_peer.h @@ -98,28 +98,29 @@ public: bool has_peer(int p_peer_id); Dictionary get_peer(int p_peer_id); Dictionary get_peers(); - void close(); // PacketPeer - Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override; ///< buffer is GONE after next get_packet - Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override; - int get_available_packet_count() const override; - int get_max_packet_size() const override; + virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override; ///< buffer is GONE after next get_packet + virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override; + virtual int get_available_packet_count() const override; + virtual int get_max_packet_size() const override; // MultiplayerPeer - void set_target_peer(int p_peer_id) override; + virtual void set_target_peer(int p_peer_id) override; - int get_unique_id() const override; - int get_packet_peer() const override; - int get_packet_channel() const override; - TransferMode get_packet_mode() const override; + virtual int get_unique_id() const override; + virtual int get_packet_peer() const override; + virtual int get_packet_channel() const override; + virtual TransferMode get_packet_mode() const override; - bool is_server() const override; - bool is_server_relay_supported() const override; + virtual bool is_server() const override; + virtual bool is_server_relay_supported() const override; - void poll() override; + virtual void poll() override; + virtual void close() override; + virtual void disconnect_peer(int p_peer_id, bool p_force = false) override; - ConnectionStatus get_connection_status() const override; + virtual ConnectionStatus get_connection_status() const override; }; #endif // WEBRTC_MULTIPLAYER_PEER_H diff --git a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml index c4481b046b..7e896a0ca3 100644 --- a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml +++ b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml @@ -10,13 +10,6 @@ <tutorials> </tutorials> <methods> - <method name="close"> - <return type="void" /> - <description> - Closes this [MultiplayerPeer], resetting the state to [constant MultiplayerPeer.CONNECTION_CONNECTED]. - [b]Note:[/b] To make sure remote peers receive a clean close prefer disconnecting clients via [method disconnect_peer]. - </description> - </method> <method name="create_client"> <return type="int" enum="Error" /> <param index="0" name="url" type="String" /> @@ -37,15 +30,6 @@ Starts a new multiplayer server listening on the given [param port]. You can optionally specify a [param bind_address], and provide a [param tls_key] and [param tls_certificate] to use TLS. </description> </method> - <method name="disconnect_peer"> - <return type="void" /> - <param index="0" name="id" type="int" /> - <param index="1" name="code" type="int" default="1000" /> - <param index="2" name="reason" type="String" default="""" /> - <description> - Disconnects the peer identified by [code]id[/code] from the server. See [method WebSocketPeer.close] for more information. - </description> - </method> <method name="get_peer" qualifiers="const"> <return type="WebSocketPeer" /> <param index="0" name="peer_id" type="int" /> diff --git a/modules/websocket/websocket_multiplayer_peer.cpp b/modules/websocket/websocket_multiplayer_peer.cpp index 0202c5bac7..827c618e4e 100644 --- a/modules/websocket/websocket_multiplayer_peer.cpp +++ b/modules/websocket/websocket_multiplayer_peer.cpp @@ -75,12 +75,10 @@ void WebSocketMultiplayerPeer::_clear() { void WebSocketMultiplayerPeer::_bind_methods() { ClassDB::bind_method(D_METHOD("create_client", "url", "verify_tls", "tls_certificate"), &WebSocketMultiplayerPeer::create_client, DEFVAL(true), DEFVAL(Ref<X509Certificate>())); ClassDB::bind_method(D_METHOD("create_server", "port", "bind_address", "tls_key", "tls_certificate"), &WebSocketMultiplayerPeer::create_server, DEFVAL("*"), DEFVAL(Ref<CryptoKey>()), DEFVAL(Ref<X509Certificate>())); - ClassDB::bind_method(D_METHOD("close"), &WebSocketMultiplayerPeer::close); ClassDB::bind_method(D_METHOD("get_peer", "peer_id"), &WebSocketMultiplayerPeer::get_peer); ClassDB::bind_method(D_METHOD("get_peer_address", "id"), &WebSocketMultiplayerPeer::get_peer_address); ClassDB::bind_method(D_METHOD("get_peer_port", "id"), &WebSocketMultiplayerPeer::get_peer_port); - ClassDB::bind_method(D_METHOD("disconnect_peer", "id", "code", "reason"), &WebSocketMultiplayerPeer::disconnect_peer, DEFVAL(1000), DEFVAL("")); ClassDB::bind_method(D_METHOD("get_supported_protocols"), &WebSocketMultiplayerPeer::get_supported_protocols); ClassDB::bind_method(D_METHOD("set_supported_protocols", "protocols"), &WebSocketMultiplayerPeer::set_supported_protocols); @@ -488,9 +486,15 @@ int WebSocketMultiplayerPeer::get_peer_port(int p_peer_id) const { return peers_map[p_peer_id]->get_connected_port(); } -void WebSocketMultiplayerPeer::disconnect_peer(int p_peer_id, int p_code, String p_reason) { +void WebSocketMultiplayerPeer::disconnect_peer(int p_peer_id, bool p_force) { ERR_FAIL_COND(!peers_map.has(p_peer_id)); - peers_map[p_peer_id]->close(p_code, p_reason); + peers_map[p_peer_id]->close(); + if (p_force) { + peers_map.erase(p_peer_id); + if (!is_server()) { + _clear(); + } + } } void WebSocketMultiplayerPeer::close() { diff --git a/modules/websocket/websocket_multiplayer_peer.h b/modules/websocket/websocket_multiplayer_peer.h index ebe013a7bf..78a58162ab 100644 --- a/modules/websocket/websocket_multiplayer_peer.h +++ b/modules/websocket/websocket_multiplayer_peer.h @@ -102,6 +102,9 @@ public: virtual int get_max_packet_size() const override; virtual bool is_server() const override; virtual void poll() override; + virtual void close() override; + virtual void disconnect_peer(int p_peer_id, bool p_force = false) override; + virtual ConnectionStatus get_connection_status() const override; /* PacketPeer */ @@ -132,8 +135,6 @@ public: IPAddress get_peer_address(int p_peer_id) const; int get_peer_port(int p_peer_id) const; - void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = ""); - void close(); void set_max_queued_packets(int p_max_queued_packets); int get_max_queued_packets() const; diff --git a/scene/main/multiplayer_peer.cpp b/scene/main/multiplayer_peer.cpp index 462dc1babb..b4e5b11abd 100644 --- a/scene/main/multiplayer_peer.cpp +++ b/scene/main/multiplayer_peer.cpp @@ -94,6 +94,8 @@ void MultiplayerPeer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_packet_mode"), &MultiplayerPeer::get_packet_mode); ClassDB::bind_method(D_METHOD("poll"), &MultiplayerPeer::poll); + ClassDB::bind_method(D_METHOD("close"), &MultiplayerPeer::close); + ClassDB::bind_method(D_METHOD("disconnect_peer", "peer", "force"), &MultiplayerPeer::disconnect_peer, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_connection_status"), &MultiplayerPeer::get_connection_status); ClassDB::bind_method(D_METHOD("get_unique_id"), &MultiplayerPeer::get_unique_id); @@ -213,6 +215,8 @@ void MultiplayerPeerExtension::_bind_methods() { GDVIRTUAL_BIND(_get_packet_peer); GDVIRTUAL_BIND(_is_server); GDVIRTUAL_BIND(_poll); + GDVIRTUAL_BIND(_close); + GDVIRTUAL_BIND(_disconnect_peer, "p_peer", "p_force"); GDVIRTUAL_BIND(_get_unique_id); GDVIRTUAL_BIND(_set_refuse_new_connections, "p_enable"); GDVIRTUAL_BIND(_is_refusing_new_connections); diff --git a/scene/main/multiplayer_peer.h b/scene/main/multiplayer_peer.h index 63ce66871e..4b5909538e 100644 --- a/scene/main/multiplayer_peer.h +++ b/scene/main/multiplayer_peer.h @@ -82,9 +82,12 @@ public: virtual TransferMode get_packet_mode() const = 0; virtual int get_packet_channel() const = 0; + virtual void disconnect_peer(int p_peer, bool p_force = false) = 0; + virtual bool is_server() const = 0; virtual void poll() = 0; + virtual void close() = 0; virtual int get_unique_id() const = 0; @@ -139,6 +142,8 @@ public: EXBIND0RC(int, get_packet_channel); EXBIND0RC(bool, is_server); EXBIND0(poll); + EXBIND0(close); + EXBIND2(disconnect_peer, int, bool); EXBIND0RC(int, get_unique_id); EXBIND0RC(ConnectionStatus, get_connection_status); }; |