summaryrefslogtreecommitdiff
path: root/modules/enet/enet_multiplayer_peer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/enet/enet_multiplayer_peer.cpp')
-rw-r--r--modules/enet/enet_multiplayer_peer.cpp247
1 files changed, 106 insertions, 141 deletions
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();
}
}