Godot Version
4.4.1
Question
I am creating a Multiplayer Game with a dedicated server. I have an Autoload singleton MultiplayerController
that, on startup, decides whether to load a server or a client scene based on whether it’s running in headless/dedicated-server mode. On the very first client start, everything works perfectly: the client scene and its UI spawn, RPCs function, etc. However, after calling my Disconnect()
method and then calling MultiplayerController.Instance.Initialize()
again, although the console logs show the client scene loading, nothing appears in the Remote tab and no client UI or logic shows up in-game. I also tried calling GetTree().ReloadCurrentScene()
instead of Initialize()
, but this did nothing.
Here some Code of my Code:
public void Disconnect()
{
GD.Print("Disconnecting from server...");
...
if (Multiplayer.MultiplayerPeer != null)
{
peer.Close();
Multiplayer.ConnectionFailed -= OnConnectionFailed;
Multiplayer.ConnectedToServer -= OnConnectedToServer;
Multiplayer.ServerDisconnected -= OnServerDisconnected;
Multiplayer.MultiplayerPeer = null;
}
GD.Print("Disconnected.");
...
MultiplayerController.Instance.Initialize();
GameState.InputEnabled = true;
}
ANd
public partial class MultiplayerController : Node
{
public static MultiplayerController Instance { get; private set; }
public bool IsServer = false;
public string GameServerScenePath = "res://Server/Scenes/GameServer.tscn";
public string ClientScenePath = "res://Client/Scenes/Client.tscn";
public override void _EnterTree()
{
if (Instance != null)
{
QueueFree();
}
Instance = this;
}
public override void _Ready()
{
Initialize();
}
public void Initialize()
{
GD.Print("MultiplayerController Initialize");
foreach (Node child in GetChildren())
{
child.QueueFree();
}
bool isHeadless = DisplayServer.GetName() == "headless" || OS.HasFeature("headless");
IsServer = OS.HasFeature("dedicated_server");
if (IsServer || isHeadless)
{
LoadServer();
}
else
{
LoadClient();
}
}
private void LoadServer()
{
GD.Print("Load GameServer ...");
var packedScene = GD.Load<PackedScene>(GameServerScenePath);
if (packedScene != null)
{
var gameServer = packedScene.Instantiate();
AddChild(gameServer);
GD.Print("GameServer loaded!");
}
else
{
GD.PushError($"GameServer scene not found at path: {GameServerScenePath}");
}
}
private void LoadClient()
{
GD.Print("Load Client ...");
var packedScene = GD.Load<PackedScene>(ClientScenePath);
if (packedScene != null)
{
Node client = packedScene.Instantiate();
AddChild(client, true);
GD.Print("Client loaded!");
}
else
{
GD.PushError($"Client scene not found at path: {ClientScenePath}");
}
}
}
Just in case it wasn’t clear, the remote scene tree has nothing to do with multiplayer. It is “remote” in the sense that it monitors the scene tree of one of the game instances you create when running the project. If you are creating multiple instances of the game to test you have to verify that you are examining the instance of the game that you want to examine. Personally, I would just print/log the multiplayer ID of the game instance and the children of your MultiplayerController, e.g. print(multiplayer.get_unique_id(), ' ', multiplayer_controller.get_children())
I actually only run one instance of the game client when testing, so I don’t think I’m accidentally inspecting the wrong Remote tree. The server is running as an exported binary and not in the editor. I went ahead and added some logging :
public void Initialize()
{
GD.Print("MultiplayerController Initialize");
GD.Print($"[Before Clear] UniqueId={Multiplayer.GetUniqueId()} ChildrenCount={GetChildren().Count}");
var children = GetChildren().ToList();
foreach (Node child in children)
{
RemoveChild(child);
child.QueueFree();
}
GD.Print($"[After Clear] UniqueId={Multiplayer.GetUniqueId()} ChildrenCount={GetChildren().Count}");
bool isHeadless = DisplayServer.GetName() == "headless" || OS.HasFeature("headless");
IsServer = OS.HasFeature("dedicated_server");
if (IsServer || isHeadless)
{
LoadServer();
}
else
{
LoadClient();
}
GD.Print($"[After Load] UniqueId={Multiplayer.GetUniqueId()} ChildrenCount={GetChildren().Count}");
foreach (var c in GetChildren()) GD.Print(" child:", c);
}
This is my Remote Tree on first start:
The MutiplayerController just spawns the NetworkManager with all its Nodes (Client Scene).
Now when press a button on the client i disconnect, so this code performs:
public async void Disconnect()
{
GD.Print("Disconnecting from server...");
if (latencyTimer != null)
{
latencyTimer.Stop();
latencyTimer.QueueFree();
latencyTimer = null;
}
Multiplayer.ConnectionFailed -= OnConnectionFailed;
Multiplayer.ConnectedToServer -= OnConnectedToServer;
Multiplayer.ServerDisconnected -= OnServerDisconnected;
if (peer != null)
{
peer.Close();
Multiplayer.MultiplayerPeer = null;
}
// Wait one frame so QueueFree() takes effect
await ToSignal(GetTree().CreateTimer(0.0), "timeout");
Multiplayer.MultiplayerPeer = new OfflineMultiplayerPeer();
GD.Print("Disconnected.");
ClientClock = 0;
latency = 0;
deltaLatency = 0;
latencyArray.Clear();
MultiplayerController.Instance.Initialize();
GameState.InputEnabled = true;
}
It should just disconnect the peer, clear all variables and start MultiplayerController.Instance.Initialize(); i basically want to go back to the very beginning of my game (GetTree().ReloadCurrentScene() didt helped).
But my Remote Tree looks like this after disconnecting:
root
---> MutiplayerController
---> Main
but as you can see in the Output log there should be something under MultiplayerController:
MultiplayerController Initialize
[Before Clear] UniqueId=1 ChildrenCount=0
[After Clear] UniqueId=1 ChildrenCount=0
Load Client ...
Client loaded!
[After Load] UniqueId=1 ChildrenCount=1
child:<Node#40902853981>
Attempting to log in with Username: test, Password: test
Connection to login server succeeded.
Requesting login with Username: testPassword: test
Reveived login request result: True
Login successful!
Connecting to server at 127.0.0.1:5000
Connection to game server succeeded.
Send ReturnToken request to server. With token: 150b8ab266970d524042c6f7ddda25b92dd08f35870da0682cecf19b663bda6c1751533618
Token verification successful!
This is me i dont need to spawn myself!
Spawn Enemy 0
Spawn Enemy 1
Disconnecting from server...
Disconnected.
MultiplayerController Initialize
[Before Clear] UniqueId=1 ChildrenCount=1
[After Clear] UniqueId=1 ChildrenCount=0
Load Client ...
Client loaded!
[After Load] UniqueId=1 ChildrenCount=1
child:<Node#93700753480>
Are you sure MultiplayerController
node isn’t just collapsed when reinitialised?
Yes, in this picture you can see, there is no arrow
And under the NetworkManager is also UI stuff, which doesnt display. my screen is just blank.