Skip to content

feat: Implement handshake over ENetMultiplayerPeer to detect closed connections#479

Merged
elementbound merged 5 commits intofoxssake:mainfrom
camperotactico:change-packet-handshake-over-enet
Aug 6, 2025
Merged

feat: Implement handshake over ENetMultiplayerPeer to detect closed connections#479
elementbound merged 5 commits intofoxssake:mainfrom
camperotactico:change-packet-handshake-over-enet

Conversation

@camperotactico
Copy link
Copy Markdown
Contributor

Hello, I have been using the Noray add-on for the last couple of days and I noticed a small issue regarding the method PacketHandshake.over_enet().

I have been using this method in a similar matter to the bootstrapper example: The host peer uses it to handshake each client peer anytime a NAT or Relay connection is received by Noray.

In my game, the issue appears when the host peer decides to close the "multiplayer lobby" (and thus disconnect from the Noray orchestrator server and freeing its multiplayer_peer) while a client peer was trying to connect.

The debugger console in Godot then gets full of error messages for the remaining duration of the timeout while loop in PacketHandshake.over_enet() as the connection is no longer active.

E 0:00:08:216   packet-handshake.gd:78 @ over_enet(): The ENetConnection instance isn't currently active.
  <C++ Error>   Parameter "host" is null.
  <C++ Source>  modules/enet/enet_connection.cpp:346 @ socket_send()
  <Stack Trace> packet-handshake.gd:78 @ over_enet()

At the moment, there is no exposed method to check whether a ENetConnection is active or not to prematurely return from the while loop before the timeout.

Because of that, I modified PacketHandshake.over_enet() to take a ENetMultiplayerPeer instead of its ENetConnection to allow to return an error if the connection with the host peer is dropped.

I am new to network stuff, so feel free to let me know if this change is not a good idea.

camperotactico and others added 4 commits July 18, 2025 12:21
…ead of a ENetConnection to allow to return an error if the connection with the host peer is dropped.
@elementbound elementbound changed the title Modify PacketHandshake.over_enet() to take an ENetMultiplayerPeer instead of a ENetConnection feat: Implement handshake over ENetMultiplayerPeer to detect closed connections Aug 5, 2025
@elementbound
Copy link
Copy Markdown
Contributor

Hey @camperotactico,

Thanks for the PR, nice catch! This does make sense, though I moved the logic into a new method instead, to not break backwards compatibility.

I couldn't reproduce the issue locally, would you mind checking that the fix still works, e.g. with Forest Brawl?

@camperotactico
Copy link
Copy Markdown
Contributor Author

Hello @elementbound,

Thanks for reviewing the changes I submitted. I just tried the new method on the Forest Brawl example and I can confirm the problem does not appear again.

What I did was to reproduce the issue first with NorayBoostrapper.gd using over_enet() (and receiving all the error messages) and then repeat using over_enet_peer() (and not receiving those errors)

By default it is not possible to reproduce the bug in Forest Brawl, as it doesn't have a "lobby room" where players can connect and disconnect freely before the game starts. I had to make a couple of changes to simulate the environment on which the error can actually appear (Similar to the project I am working on).

In my project, the error appears on the host instance of the game when the host player decides to close a lobby room right after a client peer joins it (At this point, the handshake over enet is taking place, even if both peers have already reached each other). By closing the lobby room I mean something similar to:

# close multiplayer menu screen and leave back to main menu
multiplayer.multiplayer_peer.close()
Noray.disconnect_from_host()
multiplayer_menu_screen.hide()
main_menu.show()

So, in order to simulate this in Forest Brawl, I simply modified the BrawlerSpawner class to make the host player close its multiplayer peer a couple of seconds after the client player joins the game:

func _handle_new_peer(id: int):
	...
        # Once the second player is connected, close the connection.
	if multiplayer.is_server():
		await get_tree().create_timer(2.0)
		multiplayer.multiplayer_peer.close()
		Noray.disconnect_from_host()

Obviously this example game is not accounting for that to happen, so there are other errors that appear when performing this action. However, only time-display.gd pauses the execution of the game. If I "patch" that to prevent it from blocking the excecution of the game, like:

       # line 16: add a check to ensure the multiplayer_peer is connected before updating the label values.
	if get_tree().get_multiplayer().multiplayer_peer.get_connection_status() == MultiplayerPeer.ConnectionStatus.CONNECTION_CONNECTED and not get_tree().get_multiplayer().is_server():

then the enet errors start popping up as they do on my project. I know this testing process it is a bit dirty, but I wanted to write it down in case we need to test the same issue in the future.

@elementbound
Copy link
Copy Markdown
Contributor

Thanks for the guide and the PR, @camperotactico!
And congrats on making it to the netfox contributors list 😄

@elementbound elementbound merged commit 50db161 into foxssake:main Aug 6, 2025
2 checks passed
@camperotactico
Copy link
Copy Markdown
Contributor Author

I am glad to hear that. Thanks to you as well for making this amazing asset 🫶🏻

@camperotactico camperotactico deleted the change-packet-handshake-over-enet branch August 7, 2025 08:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants