godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
89.04k stars 20.19k forks source link

ENET server disconnects client due to timeout caused by loading a level. #40618

Closed Griefchief closed 3 years ago

Griefchief commented 4 years ago

Godot version: 3.2.2 stable Had no problems on 3.2.1 with networking at all, was enet timeout check changed?

OS/device including version: Win 10

Issue description:

ENET timeouts need to not fire during client timeouts caused by heavy workload on the client side. This is especially prevalent on DEBUG builds.

Steps to reproduce: You need a heavy build like mine, you try to connect and see a timeout on the server.

You then setup a breakpoint on the server in thirdparty/enet/protocol.c, line 1457

And try to connect a client that loads a massive 40mb pngs and a 7-15 second level with terrain and other GDScript/code heavy stuff.

Enet will dissconect the client from the server here (this is serverside code): https://github.com/godotengine/godot/blob/3.2.2-stable/thirdparty/enet/protocol.c#L1457

P.S. Loading a level is a chicken and an egg problem. You shoudn't load a level without connecting first, but then chocked main? thread needs to not choke enet while loading happens and force a server to dc the client.

Minimal reproduction project:

Soon, I hope. For now I'm just documenting this while I try to fix this and another Enet disconnection issue with my project that happens later also only on 3.2.2.

Griefchief commented 4 years ago

What is the point of timeoutMaximum if it's 30 seconds will never be reached if I understand the remaining two and the || (OR) correctly? image

edit: Definitely a || timeout: image

thirdparty/enet/time.h

#define ENET_TIME_DIFFERENCE(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW ? (b) - (a) : (a) - (b))
Calinou commented 4 years ago

cc @Faless

arnerak commented 4 years ago

As a workaround, you could try

func _ready():
    get_tree().multiplayer_poll = false

func _physics_process(delta):
    get_tree().multiplayer.poll()

given that _physics_process still runs normally during heavy load, which it should?

MikeSchulze commented 3 years ago

@arnerak your recommended solution not works. _physics_process is also blocked when the _process is blocked for a while is all running in the main thread But your hint kicks me in the right direction I run a thread where do the poll to hold the connection alive. So on debuging and stay longer in a function do not kills the connection anymore.

MikeSchulze commented 3 years ago

Update, I run a thread where do the poll to hold the connection alive. is not working right it kills the option to debug

Any Update here? I have still the same problem when i stop at a breakpoint on client side the connection is closed around 30s. So it is currently not possible to debug a client.

icolwell commented 3 years ago

Recent PR merge will likely help or completely resolve this issue. It exposes timeout settings: https://github.com/godotengine/godot/pull/46470

Faless commented 3 years ago

As reported by @icolwell you can now configure the timeout if desired. Of course, I still suggest trying to offload most of the heavy code outside the main thread, by using things like ResourceInteractiveLoader and Threads if needed.

Closing.