diff options
-rw-r--r-- | doc/classes/AnimationNode.xml | 2 | ||||
-rw-r--r-- | doc/classes/Directory.xml | 10 | ||||
-rw-r--r-- | doc/classes/HMACContext.xml | 84 | ||||
-rw-r--r-- | doc/classes/PacketPeerUDP.xml | 56 | ||||
-rw-r--r-- | doc/classes/PhysicsServer3D.xml | 1 | ||||
-rw-r--r-- | doc/classes/RDFramebufferPass.xml | 2 | ||||
-rw-r--r-- | drivers/unix/dir_access_unix.cpp | 16 | ||||
-rw-r--r-- | drivers/unix/dir_access_unix.h | 1 | ||||
-rw-r--r-- | modules/enet/enet_connection.cpp | 88 | ||||
-rw-r--r-- | modules/enet/enet_connection.h | 2 | ||||
-rw-r--r-- | modules/enet/enet_multiplayer_peer.cpp | 261 | ||||
-rw-r--r-- | modules/enet/enet_multiplayer_peer.h | 6 |
12 files changed, 288 insertions, 241 deletions
diff --git a/doc/classes/AnimationNode.xml b/doc/classes/AnimationNode.xml index c9d8ae9936..08290523f7 100644 --- a/doc/classes/AnimationNode.xml +++ b/doc/classes/AnimationNode.xml @@ -5,7 +5,7 @@ </brief_description> <description> Base resource for [AnimationTree] nodes. In general, it's not used directly, but you can create custom ones with custom blending formulas. - Inherit this when creating nodes mainly for use in [AnimationNodeBlendTree], otherwise [AnimationRootNode] should be used instead. + Inherit this when creating nodes mainly for use in [AnimationNodeBlendTree], otherwise [AnimationRootNode] should be used instead. </description> <tutorials> <link title="AnimationTree">$DOCS_URL/tutorials/animation/animation_tree.html</link> diff --git a/doc/classes/Directory.xml b/doc/classes/Directory.xml index dbf5e31da4..3f0a5610b1 100644 --- a/doc/classes/Directory.xml +++ b/doc/classes/Directory.xml @@ -119,13 +119,19 @@ <return type="String" /> <argument index="0" name="idx" type="int" /> <description> - On Windows, returns the name of the drive (partition) passed as an argument (e.g. [code]C:[/code]). On other platforms, or if the requested drive does not exist, the method returns an empty String. + On Windows, returns the name of the drive (partition) passed as an argument (e.g. [code]C:[/code]). + On macOS, returns the path to the mounted volume passed as an argument. + On Linux, returns the path to the mounted volume or GTK 3 bookmark passed as an argument. + On other platforms, or if the requested drive does not exist, the method returns an empty String. </description> </method> <method name="get_drive_count"> <return type="int" /> <description> - On Windows, returns the number of drives (partitions) mounted on the current filesystem. On other platforms, the method returns 0. + On Windows, returns the number of drives (partitions) mounted on the current filesystem. + On macOS, returns the number of mounted volumes. + On Linux, returns the number of mounted volumes and GTK 3 bookmarks. + On other platforms, the method returns 0. </description> </method> <method name="get_files"> diff --git a/doc/classes/HMACContext.xml b/doc/classes/HMACContext.xml index 69ad194fe0..b29f821da5 100644 --- a/doc/classes/HMACContext.xml +++ b/doc/classes/HMACContext.xml @@ -5,52 +5,52 @@ </brief_description> <description> The HMACContext class is useful for advanced HMAC use cases, such as streaming the message as it supports creating the message over time rather than providing it all at once. - [codeblocks] - [gdscript] - extends Node - var ctx = HMACContext.new() + [codeblocks] + [gdscript] + extends Node + var ctx = HMACContext.new() - func _ready(): - var key = "supersecret".to_utf8() - var err = ctx.start(HashingContext.HASH_SHA256, key) - assert(err == OK) - var msg1 = "this is ".to_utf8() - var msg2 = "vewy vewy secret".to_utf8() - err = ctx.update(msg1) - assert(err == OK) - err = ctx.update(msg2) - assert(err == OK) - var hmac = ctx.finish() - print(hmac.hex_encode()) + func _ready(): + var key = "supersecret".to_utf8() + var err = ctx.start(HashingContext.HASH_SHA256, key) + assert(err == OK) + var msg1 = "this is ".to_utf8() + var msg2 = "vewy vewy secret".to_utf8() + err = ctx.update(msg1) + assert(err == OK) + err = ctx.update(msg2) + assert(err == OK) + var hmac = ctx.finish() + print(hmac.hex_encode()) - [/gdscript] - [csharp] - using Godot; - using System; - using System.Diagnostics; + [/gdscript] + [csharp] + using Godot; + using System; + using System.Diagnostics; - public class CryptoNode : Node - { - private HMACContext ctx = new HMACContext(); - public override void _Ready() - { - PackedByteArray key = String("supersecret").to_utf8(); - Error err = ctx.Start(HashingContext.HASH_SHA256, key); - GD.Assert(err == OK); - PackedByteArray msg1 = String("this is ").to_utf8(); - PackedByteArray msg2 = String("vewy vew secret").to_utf8(); - err = ctx.Update(msg1); - GD.Assert(err == OK); - err = ctx.Update(msg2); - GD.Assert(err == OK); - PackedByteArray hmac = ctx.Finish(); - GD.Print(hmac.HexEncode()); - } - } + public class CryptoNode : Node + { + private HMACContext ctx = new HMACContext(); + public override void _Ready() + { + PackedByteArray key = String("supersecret").to_utf8(); + Error err = ctx.Start(HashingContext.HASH_SHA256, key); + GD.Assert(err == OK); + PackedByteArray msg1 = String("this is ").to_utf8(); + PackedByteArray msg2 = String("vewy vew secret").to_utf8(); + err = ctx.Update(msg1); + GD.Assert(err == OK); + err = ctx.Update(msg2); + GD.Assert(err == OK); + PackedByteArray hmac = ctx.Finish(); + GD.Print(hmac.HexEncode()); + } + } - [/csharp] - [/codeblocks] - [b]Note:[/b] Not available in HTML5 exports. + [/csharp] + [/codeblocks] + [b]Note:[/b] Not available in HTML5 exports. </description> <tutorials> </tutorials> diff --git a/doc/classes/PacketPeerUDP.xml b/doc/classes/PacketPeerUDP.xml index 31640eb3d8..cefb74191e 100644 --- a/doc/classes/PacketPeerUDP.xml +++ b/doc/classes/PacketPeerUDP.xml @@ -107,36 +107,36 @@ <description> Waits for a packet to arrive on the bound address. See [method bind]. [b]Note:[/b] [method wait] can't be interrupted once it has been called. This can be worked around by allowing the other party to send a specific "death pill" packet like this: - [codeblocks] - [gdscript] - socket = PacketPeerUDP.new() - # Server - socket.set_dest_address("127.0.0.1", 789) - socket.put_packet("Time to stop".to_ascii()) + [codeblocks] + [gdscript] + socket = PacketPeerUDP.new() + # Server + socket.set_dest_address("127.0.0.1", 789) + socket.put_packet("Time to stop".to_ascii()) - # Client - while socket.wait() == OK: - var data = socket.get_packet().get_string_from_ascii() - if data == "Time to stop": - return - [/gdscript] - [csharp] - var socket = new PacketPeerUDP(); - // Server - socket.SetDestAddress("127.0.0.1", 789); - socket.PutPacket("Time to stop".ToAscii()); + # Client + while socket.wait() == OK: + var data = socket.get_packet().get_string_from_ascii() + if data == "Time to stop": + return + [/gdscript] + [csharp] + var socket = new PacketPeerUDP(); + // Server + socket.SetDestAddress("127.0.0.1", 789); + socket.PutPacket("Time to stop".ToAscii()); - // Client - while (socket.Wait() == OK) - { - string data = socket.GetPacket().GetStringFromASCII(); - if (data == "Time to stop") - { - return; - } - } - [/csharp] - [/codeblocks] + // Client + while (socket.Wait() == OK) + { + string data = socket.GetPacket().GetStringFromASCII(); + if (data == "Time to stop") + { + return; + } + } + [/csharp] + [/codeblocks] </description> </method> </methods> diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml index 16c195c6dc..cb90d84238 100644 --- a/doc/classes/PhysicsServer3D.xml +++ b/doc/classes/PhysicsServer3D.xml @@ -336,7 +336,6 @@ <argument index="0" name="body" type="RID" /> <description> Returns the physics layer or layers a body can collide with. -- </description> </method> <method name="body_get_constant_force" qualifiers="const"> diff --git a/doc/classes/RDFramebufferPass.xml b/doc/classes/RDFramebufferPass.xml index 4469a5d447..33e4248983 100644 --- a/doc/classes/RDFramebufferPass.xml +++ b/doc/classes/RDFramebufferPass.xml @@ -5,7 +5,7 @@ </brief_description> <description> This class contains the list of attachment descriptions for a framebuffer pass. Each points with an index to a previously supplied list of texture attachments. - Multipass framebuffers can optimize some configurations in mobile, on desktop they provide little to no advantage. + Multipass framebuffers can optimize some configurations in mobile, on desktop they provide little to no advantage. </description> <tutorials> </tutorials> diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp index be993b88e5..f263a8b62b 100644 --- a/drivers/unix/dir_access_unix.cpp +++ b/drivers/unix/dir_access_unix.cpp @@ -216,6 +216,8 @@ static bool _filter_drive(struct mntent *mnt) { #endif static void _get_drives(List<String> *list) { + list->push_back("/"); + #if defined(HAVE_MNTENT) && defined(X11_ENABLED) // Check /etc/mtab for the list of mounted partitions FILE *mtab = setmntent("/etc/mtab", "r"); @@ -286,6 +288,20 @@ String DirAccessUnix::get_drive(int p_drive) { return list[p_drive]; } +int DirAccessUnix::get_current_drive() { + int drive = 0; + int max_length = -1; + const String path = get_current_dir().to_lower(); + for (int i = 0; i < get_drive_count(); i++) { + const String d = get_drive(i).to_lower(); + if (max_length < d.length() && path.begins_with(d)) { + max_length = d.length(); + drive = i; + } + } + return drive; +} + bool DirAccessUnix::drives_are_shortcuts() { return true; } diff --git a/drivers/unix/dir_access_unix.h b/drivers/unix/dir_access_unix.h index 8b19308967..327707de00 100644 --- a/drivers/unix/dir_access_unix.h +++ b/drivers/unix/dir_access_unix.h @@ -63,6 +63,7 @@ public: virtual int get_drive_count(); virtual String get_drive(int p_drive); + virtual int get_current_drive(); virtual bool drives_are_shortcuts(); virtual Error change_dir(String p_dir); ///< can be relative or absolute, return false on success diff --git a/modules/enet/enet_connection.cpp b/modules/enet/enet_connection.cpp index e833264d6a..62f03b444b 100644 --- a/modules/enet/enet_connection.cpp +++ b/modules/enet/enet_connection.cpp @@ -117,58 +117,36 @@ Ref<ENetPacketPeer> ENetConnection::connect_to_host(const String &p_address, int return out; } -ENetConnection::EventType ENetConnection::service(int p_timeout, Event &r_event) { - ERR_FAIL_COND_V_MSG(!host, EVENT_ERROR, "The ENetConnection instance isn't currently active."); - ERR_FAIL_COND_V(r_event.peer.is_valid(), EVENT_ERROR); - - // Drop peers that have already been disconnected. - // NOTE: Forcibly disconnected peers (i.e. peers disconnected via - // enet_peer_disconnect*) do not trigger DISCONNECTED events. - List<Ref<ENetPacketPeer>>::Element *E = peers.front(); - while (E) { - if (!E->get()->is_active()) { - peers.erase(E->get()); - } - E = E->next(); - } - - ENetEvent event; - int ret = enet_host_service(host, &event, p_timeout); - - if (ret < 0) { - return EVENT_ERROR; - } else if (ret == 0) { - return EVENT_NONE; - } - switch (event.type) { +ENetConnection::EventType ENetConnection::_parse_event(const ENetEvent &p_event, Event &r_event) { + switch (p_event.type) { case ENET_EVENT_TYPE_CONNECT: { - if (event.peer->data == nullptr) { - Ref<ENetPacketPeer> pp = memnew(ENetPacketPeer(event.peer)); + if (p_event.peer->data == nullptr) { + Ref<ENetPacketPeer> pp = memnew(ENetPacketPeer(p_event.peer)); peers.push_back(pp); } - r_event.peer = Ref<ENetPacketPeer>((ENetPacketPeer *)event.peer->data); - r_event.data = event.data; + r_event.peer = Ref<ENetPacketPeer>((ENetPacketPeer *)p_event.peer->data); + r_event.data = p_event.data; return EVENT_CONNECT; } break; case ENET_EVENT_TYPE_DISCONNECT: { // A peer disconnected. - if (event.peer->data != nullptr) { - Ref<ENetPacketPeer> pp = Ref<ENetPacketPeer>((ENetPacketPeer *)event.peer->data); + if (p_event.peer->data != nullptr) { + Ref<ENetPacketPeer> pp = Ref<ENetPacketPeer>((ENetPacketPeer *)p_event.peer->data); pp->_on_disconnect(); peers.erase(pp); r_event.peer = pp; - r_event.data = event.data; + r_event.data = p_event.data; return EVENT_DISCONNECT; } return EVENT_ERROR; } break; case ENET_EVENT_TYPE_RECEIVE: { // Packet reveived. - if (event.peer->data != nullptr) { - Ref<ENetPacketPeer> pp = Ref<ENetPacketPeer>((ENetPacketPeer *)event.peer->data); - r_event.peer = Ref<ENetPacketPeer>((ENetPacketPeer *)event.peer->data); - r_event.channel_id = event.channelID; - r_event.packet = event.packet; + if (p_event.peer->data != nullptr) { + Ref<ENetPacketPeer> pp = Ref<ENetPacketPeer>((ENetPacketPeer *)p_event.peer->data); + r_event.peer = Ref<ENetPacketPeer>((ENetPacketPeer *)p_event.peer->data); + r_event.channel_id = p_event.channelID; + r_event.packet = p_event.packet; return EVENT_RECEIVE; } return EVENT_ERROR; @@ -180,6 +158,44 @@ ENetConnection::EventType ENetConnection::service(int p_timeout, Event &r_event) } } +ENetConnection::EventType ENetConnection::service(int p_timeout, Event &r_event) { + ERR_FAIL_COND_V_MSG(!host, EVENT_ERROR, "The ENetConnection instance isn't currently active."); + ERR_FAIL_COND_V(r_event.peer.is_valid(), EVENT_ERROR); + + // Drop peers that have already been disconnected. + // NOTE: Forcibly disconnected peers (i.e. peers disconnected via + // enet_peer_disconnect*) do not trigger DISCONNECTED events. + List<Ref<ENetPacketPeer>>::Element *E = peers.front(); + while (E) { + if (!E->get()->is_active()) { + peers.erase(E->get()); + } + E = E->next(); + } + + ENetEvent event; + int ret = enet_host_service(host, &event, p_timeout); + + if (ret < 0) { + return EVENT_ERROR; + } else if (ret == 0) { + return EVENT_NONE; + } + return _parse_event(event, r_event); +} + +int ENetConnection::check_events(EventType &r_type, Event &r_event) { + ERR_FAIL_COND_V_MSG(!host, -1, "The ENetConnection instance isn't currently active."); + ENetEvent event; + int ret = enet_host_check_events(host, &event); + if (ret < 0) { + r_type = EVENT_ERROR; + return ret; + } + r_type = _parse_event(event, r_event); + return ret; +} + void ENetConnection::flush() { ERR_FAIL_COND_MSG(!host, "The ENetConnection instance isn't currently active."); enet_host_flush(host); diff --git a/modules/enet/enet_connection.h b/modules/enet/enet_connection.h index 0f7744953e..bffda81906 100644 --- a/modules/enet/enet_connection.h +++ b/modules/enet/enet_connection.h @@ -79,6 +79,7 @@ private: ENetHost *host = nullptr; List<Ref<ENetPacketPeer>> peers; + EventType _parse_event(const ENetEvent &p_event, Event &r_event); Error _create(ENetAddress *p_address, int p_max_peers, int p_max_channels, int p_in_bandwidth, int p_out_bandwidth); Array _service(int p_timeout = 0); void _broadcast(int p_channel, PackedByteArray p_packet, int p_flags); @@ -110,6 +111,7 @@ public: void destroy(); Ref<ENetPacketPeer> connect_to_host(const String &p_address, int p_port, int p_channels, int p_data = 0); EventType service(int p_timeout, Event &r_event); + int check_events(EventType &r_type, Event &r_event); void flush(); void bandwidth_limit(int p_in_bandwidth = 0, int p_out_bandwidth = 0); void channel_limit(int p_max_channels); diff --git a/modules/enet/enet_multiplayer_peer.cpp b/modules/enet/enet_multiplayer_peer.cpp index 2cfae60ad2..cb22d349f8 100644 --- a/modules/enet/enet_multiplayer_peer.cpp +++ b/modules/enet/enet_multiplayer_peer.cpp @@ -114,32 +114,21 @@ Error ENetMultiplayerPeer::add_mesh_peer(int p_id, Ref<ENetConnection> p_host) { return OK; } -bool ENetMultiplayerPeer::_poll_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 true; - } - switch (ret) { +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()) { - event.peer->reset(); + p_event.peer->reset(); return false; } // Client joined with invalid ID, probably trying to exploit us. - if (event.data < 2 || peers.has((int)event.data)) { - event.peer->reset(); + if (p_event.data < 2 || peers.has((int)p_event.data)) { + p_event.peer->reset(); return false; } - int id = event.data; - event.peer->set_meta(SNAME("_net_id"), id); - peers[id] = event.peer; + 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); if (server_relay) { @@ -148,7 +137,7 @@ bool ENetMultiplayerPeer::_poll_server() { return false; } case ENetConnection::EVENT_DISCONNECT: { - int id = event.peer->get_meta(SNAME("_net_id")); + int id = p_event.peer->get_meta(SNAME("_net_id")); if (!peers.has(id)) { // Never fully connected. return false; @@ -162,28 +151,28 @@ bool ENetMultiplayerPeer::_poll_server() { return false; } case ENetConnection::EVENT_RECEIVE: { - if (event.channel_id == SYSCH_CONFIG) { - _destroy_unused(event.packet); + if (p_event.channel_id == SYSCH_CONFIG) { + _destroy_unused(p_event.packet); ERR_FAIL_V_MSG(false, "Only server can send config messages"); } else { - if (event.packet->dataLength < 8) { - _destroy_unused(event.packet); + if (p_event.packet->dataLength < 8) { + _destroy_unused(p_event.packet); ERR_FAIL_V_MSG(false, "Invalid packet size"); } - uint32_t source = decode_uint32(&event.packet->data[0]); - int target = decode_uint32(&event.packet->data[4]); + uint32_t source = decode_uint32(&p_event.packet->data[0]); + int target = decode_uint32(&p_event.packet->data[4]); - uint32_t id = event.peer->get_meta(SNAME("_net_id")); + uint32_t id = p_event.peer->get_meta(SNAME("_net_id")); // Someone is cheating and trying to fake the source! if (source != id) { - _destroy_unused(event.packet); + _destroy_unused(p_event.packet); ERR_FAIL_V_MSG(false, "Someone is cheating and trying to fake the source!"); } Packet packet; - packet.packet = event.packet; - packet.channel = event.channel_id; + packet.packet = p_event.packet; + packet.channel = p_event.channel_id; packet.from = id; // Even if relaying is disabled, these targets are valid as incoming packets. @@ -194,9 +183,9 @@ bool ENetMultiplayerPeer::_poll_server() { if (server_relay && target != 1) { packet.packet->referenceCount++; - _relay(source, target, event.channel_id, event.packet); + _relay(source, target, p_event.channel_id, p_event.packet); packet.packet->referenceCount--; - _destroy_unused(event.packet); + _destroy_unused(p_event.packet); } // Destroy packet later } @@ -207,23 +196,8 @@ bool ENetMultiplayerPeer::_poll_server() { } } -bool ENetMultiplayerPeer::_poll_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(); - return true; - } - ENetConnection::Event event; - ENetConnection::EventType ret = hosts[0]->service(0, event); - if (ret == ENetConnection::EVENT_ERROR) { - return true; - } - switch (ret) { +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); @@ -241,15 +215,15 @@ bool ENetMultiplayerPeer::_poll_client() { return true; } case ENetConnection::EVENT_RECEIVE: { - if (event.channel_id == SYSCH_CONFIG) { + if (p_event.channel_id == SYSCH_CONFIG) { // Config message - if (event.packet->dataLength != 8) { - _destroy_unused(event.packet); + if (p_event.packet->dataLength != 8) { + _destroy_unused(p_event.packet); ERR_FAIL_V(false); } - int msg = decode_uint32(&event.packet->data[0]); - int id = decode_uint32(&event.packet->data[4]); + int msg = decode_uint32(&p_event.packet->data[0]); + int id = decode_uint32(&p_event.packet->data[4]); switch (msg) { case SYSMSG_ADD_PEER: { @@ -262,18 +236,18 @@ bool ENetMultiplayerPeer::_poll_client() { emit_signal(SNAME("peer_disconnected"), id); } break; } - _destroy_unused(event.packet); + _destroy_unused(p_event.packet); } else { - if (event.packet->dataLength < 8) { - _destroy_unused(event.packet); + if (p_event.packet->dataLength < 8) { + _destroy_unused(p_event.packet); ERR_FAIL_V_MSG(false, "Invalid packet size"); } - uint32_t source = decode_uint32(&event.packet->data[0]); + uint32_t source = decode_uint32(&p_event.packet->data[0]); Packet packet; - packet.packet = event.packet; + packet.packet = p_event.packet; packet.from = source; - packet.channel = event.channel_id; + packet.channel = p_event.channel_id; packet.packet->referenceCount++; incoming_packets.push_back(packet); @@ -286,61 +260,37 @@ bool ENetMultiplayerPeer::_poll_client() { } } -bool ENetMultiplayerPeer::_poll_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); +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); } - } - } - bool should_stop = true; - 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(p_peer_id); + return true; + case ENetConnection::EVENT_RECEIVE: { + if (p_event.packet->dataLength < 8) { + _destroy_unused(p_event.packet); + ERR_FAIL_V_MSG(false, "Invalid packet size"); } - hosts.erase(E.key); - continue; - } - switch (ret) { - case ENetConnection::EVENT_CONNECT: - should_stop = false; - event.peer->reset(); - break; - case ENetConnection::EVENT_DISCONNECT: - should_stop = false; - if (peers.has(E.key)) { - emit_signal(SNAME("peer_disconnected"), E.key); - peers.erase(E.key); - } - hosts.erase(E.key); - break; - case ENetConnection::EVENT_RECEIVE: { - should_stop = false; - if (event.packet->dataLength < 8) { - _destroy_unused(event.packet); - ERR_CONTINUE_MSG(true, "Invalid packet size"); - } - Packet packet; - packet.packet = event.packet; - packet.from = E.key; - packet.channel = event.channel_id; + Packet packet; + packet.packet = p_event.packet; + packet.from = p_peer_id; + packet.channel = p_event.channel_id; - packet.packet->referenceCount++; - incoming_packets.push_back(packet); - } break; - default: - break; // Nothing to do - } + packet.packet->referenceCount++; + incoming_packets.push_back(packet); + return false; + } break; + default: + // Nothing to do + return true; } - return should_stop; } void ENetMultiplayerPeer::poll() { @@ -348,26 +298,77 @@ void ENetMultiplayerPeer::poll() { _pop_current_packet(); - while (true) { - switch (active_mode) { - case MODE_CLIENT: - if (_poll_client()) { - return; + 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")); } - break; - case MODE_SERVER: - if (_poll_server()) { + close_connection(); + 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; } - break; - case MODE_MESH: - if (_poll_mesh()) { - return; + } while (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); } - break; - default: + } + 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; + } + } while (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); + } + } + } + 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)) { + break; // Keep polling the others. + } + } while (E.value->check_events(ret, event) > 0); + } + } break; + default: + return; } } @@ -441,11 +442,11 @@ Error ENetMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size } else { switch (get_transfer_mode()) { case Multiplayer::TRANSFER_MODE_UNRELIABLE: { - packet_flags = ENET_PACKET_FLAG_UNSEQUENCED; + packet_flags = ENET_PACKET_FLAG_UNSEQUENCED | ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT; channel = SYSCH_UNRELIABLE; } break; case Multiplayer::TRANSFER_MODE_UNRELIABLE_ORDERED: { - packet_flags = 0; + packet_flags = ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT; channel = SYSCH_UNRELIABLE; } break; case Multiplayer::TRANSFER_MODE_RELIABLE: { @@ -455,6 +456,12 @@ Error ENetMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size } } +#ifdef DEBUG_ENABLED + if ((packet_flags & ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT) && p_buffer_size + 8 > ENET_HOST_DEFAULT_MTU) { + WARN_PRINT_ONCE(vformat("Sending %d bytes unrealiably which is above the MTU (%d), this will result in higher packet loss", p_buffer_size + 8, ENET_HOST_DEFAULT_MTU)); + } +#endif + ENetPacket *packet = enet_packet_create(nullptr, p_buffer_size + 8, packet_flags); encode_uint32(unique_id, &packet->data[0]); // Source ID encode_uint32(target_peer, &packet->data[4]); // Dest ID diff --git a/modules/enet/enet_multiplayer_peer.h b/modules/enet/enet_multiplayer_peer.h index 7a60e2359c..abec1e432e 100644 --- a/modules/enet/enet_multiplayer_peer.h +++ b/modules/enet/enet_multiplayer_peer.h @@ -84,9 +84,9 @@ private: Packet current_packet; void _pop_current_packet(); - bool _poll_server(); - bool _poll_client(); - bool _poll_mesh(); + 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 _relay(int p_from, int p_to, enet_uint8 p_channel, ENetPacket *p_packet); void _notify_peers(int p_id, bool p_connected); void _destroy_unused(ENetPacket *p_packet); |