Weird behaviour when closing a multiplayer game on Windows

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By gerep

Hi all,

I am working on a peer-to-peer Pong game.

My issue now is on Windows when the host closes the game window.

I am using the following function to capture when the game window is closed:

func _notification(what):
	if what == MainLoop.NOTIFICATION_WM_QUIT_REQUEST:
		if get_tree().network_peer != null:
			rpc_id(0, "stop_game", get_instance_id())

		get_tree().quit()

I tell the connected client to stop their execution of the game physics and load the initial screen again.

remote func stop_game(_requester) -> void:
	get_tree().network_peer = null
	get_tree().call_group_flags(SceneTree.GROUP_CALL_REALTIME, "player", "stop_network_tickrate")
	get_tree().call_group_flags(SceneTree.GROUP_CALL_REALTIME, "player", "stop_physics")
	get_tree().call_group_flags(SceneTree.GROUP_CALL_REALTIME, "BallGroup", "stop_physics")
	get_tree().change_scene_to(network_setup_scene)

This code works as expected when playing the game on Linux or macOS but not on Windows.

I have those “helper” functions on my player and ball scenes that will stop the physics execution and also a timer that I use.

For the player:

func stop_network_tickrate() -> void:
	print("player stop_network_tickrate")
	$NetworkTickRate.stop()

func stop_physics() -> void:
	print("player stop_physics")
	set_physics_process(false)

For the ball:

func stop_physics() -> void:
	print("ball stop_physics")
	set_physics_process(false)

I have added those print statements to make sure those functions were being called. I can see those on my output console:

player stop_network_tickrate
player stop_network_tickrate
player stop_physics
player stop_physics
ball stop_physics

The need to stop the physics process is because I am calling is_network_master, which fails when there is no peer connected to the network.

func _physics_process(delta) -> void:
	if is_network_master():
		rset_unreliable("puppet_velocity", velocity)
	else:
		velocity = puppet_velocity

The error message was like this:

get_unique_id: The multiplayer instance isn't currently active.   <C++ Error>   Condition "!active" is true. Returned: 0   <C++ Source>  modules/enet/networked_multiplayer_enet.cpp:658 @ get_unique_id()   <Stack Trace> player.gd:42 @ _on_NetworkTickRate_timeout()

But when I close the game windows on Windows, it doesn’t even call the stop_game function.

Any suggestions on what is happening? Also, do you have any suggestions on a different way of managing that?

Thank you.

:bust_in_silhouette: Reply From: omggomb

After some testing my guess is, that the game quits too fast for the message to be sent. Why this is only a problem on windows I have no idea though.

With my crude test setup I was able to get it to work by first disabling the auto quit function of the scene tree (get_tree().auto_accept_quit = false). This way, pressing close won’t actually close the window until you call get_tree().quit() from the notification.

Then inserting a small delay between the RPC and the quit invocation made the rpc go through:

rpc_id(0, ....)
yield(get_tree().create_timer(1), "timeout")
get_tree.quit()

Thank you, I’ll give it a try.

I have added the timer as you did but not auto_accept_quit. It was quitting without waiting for the timeout.

I’ll let you know if it works.

gerep | 2022-12-01 13:46

This was the answer my friend, hats off to you!

Extremos | 2022-12-01 13:52