CSharpRedotTools / Template

A template used for quickly setting up new Redot 4 C# games.
MIT License
111 stars 8 forks source link

[Netcode] Clicking "Stop Server" does not stop the server #20

Closed valkyrienyanko closed 2 months ago

valkyrienyanko commented 2 months ago

https://github.com/user-attachments/assets/2c28e2d1-76e4-4664-ae0f-0b920ff71d91

Steps to Reproduce:

  1. Download .NET version of Godot 4
  2. Clone https://github.com/ValksGodotTools/Template
  3. Set the main scene to res://2D Top Down/level_2D_top_down.tscn
  4. Launch 1 instance of the game
  5. Start the server and connect the client to it
  6. Disconnect client
  7. Click on stop server

[!IMPORTANT] You will get a message in the console saying "The server has stopped already" when in fact it has not stopped.

Observation

For some reason when the client disconnects and sets _running = 0 for the client, it also sets _running = 0 for the server. This can be seen when running the following console command after the client disconnects.

[!TIP] Press F12 to bring up the in-game console. Type debug and hit Enter to execute this command in the console.

[ConsoleCommand("debug")]
void Debug()
{
    Game.Log(Global.Services.Get<Net>().Server.IsRunning);
}

Relevant Code

https://github.com/ValksGodotTools/Template/blob/17f1637bf362016b6a3ac4e84fc5679fd8881773/Scripts/UI/UINetControlPanel.cs#L22

https://github.com/ValksGodotTools/Template/blob/17f1637bf362016b6a3ac4e84fc5679fd8881773/Scripts/UI/UINetControlPanel.cs#L19

[!NOTE] ENetServer and ENetClient both start new tasks on a function named "WorkerThread". These functions are named the same but are 2 completely different functions.

https://github.com/ValksGodotTools/Template/blob/a67b9a0b848cb9aaad2f3d044183e254e2eedf6e/Template/Scripts/Netcode/ENetClient.cs#L44-L53

https://github.com/ValksGodotTools/Template/blob/a67b9a0b848cb9aaad2f3d044183e254e2eedf6e/Template/Scripts/Netcode/ENetServer.cs#L26-L47

[!NOTE] ENetServer and ENetClient both extend from ENetLow

https://github.com/ValksGodotTools/Template/blob/a67b9a0b848cb9aaad2f3d044183e254e2eedf6e/Template/Scripts/Netcode/ENetLow.cs#L90

valkyrienyanko commented 2 months ago

I found out the reason this is happening.

client.OnDisconnected += opcode =>
{
    Game.SceneManager.ResetCurrentScene();
};

The entire scene is reset when client disconnects. So of course the server will reset but still remain active since its running on a separate thread.

I need to find a way to reset the entire scene without resetting the game server thread.

valkyrienyanko commented 2 months ago
client.OnDisconnected += opcode =>
{
    // The entire scene cannot be reset here because this will also reset the
    // instance stored for both GameServer and GameClient. These run on separate
    // threads, so resetting them here won't stop them on the other threads. Not
    // to mention they shouldn't be reset in the first place! So this is why the
    // entire scene is no longer reset when the client disconnects.
    // See https://github.com/ValksGodotTools/Template/issues/20 for more info
    // about this.
    Player.QueueFree();

    OtherPlayers.Values.ForEach(x => x.QueueFree());
};

This will be the solution for now. I will just have to remember to reset or QueueFree() anything in the future in this area.