|
@@ -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();
|
|
|
}
|
|
|
}
|
|
|
|