public partial class MultiplayerManager : Node { [Export] public Player LocalPlayer { get; set; } [Export] public Node3D Players { get; set; } [Export] public PackedScene PlayerScene { get; set; } public event Action PlayerJoined; public event Action PlayerLeft; public override void _Ready() { Multiplayer.ConnectedToServer += OnMultiplayerReady; Multiplayer.ServerDisconnected += OnMultiplayerDisconnected; Multiplayer.PeerConnected += OnPeerConnected; Multiplayer.PeerDisconnected += OnPeerDisconnected; } public Player GetPlayerByPeerId(int peerId) => Players.GetNode(peerId.ToString()); public void Connect(string address, ushort port) { var peer = new ENetMultiplayerPeer(); peer.CreateClient(address, port); Multiplayer.MultiplayerPeer = peer; } public bool CreateServer(ushort port) { var peer = new ENetMultiplayerPeer(); if (peer.CreateServer(port) == Error.Ok) { Multiplayer.MultiplayerPeer = peer; OnMultiplayerReady(); return true; } else return false; } public void Disconnect() => OnMultiplayerDisconnected(); void OnMultiplayerReady() { var localId = Multiplayer.GetUniqueId(); LocalPlayer.PeerId = localId; LocalPlayer.SetMultiplayerAuthority(localId); if (!Multiplayer.IsServer()) // Spawn players for all the other peers. This excludes the server, // since `OnPeerConnected` will already be called for it on connecting. foreach (var peerId in Multiplayer.GetPeers()) if (peerId != 1) OnPeerConnected(peerId); } void OnMultiplayerDisconnected() { foreach (var player in Players.GetChildren().Cast()) { if (player.IsLocal) player.PeerId = 0; else OnPeerDisconnected(player.PeerId); } Multiplayer.MultiplayerPeer.Close(); Multiplayer.MultiplayerPeer = null; } void OnPeerConnected(long peerId) { var player = PlayerScene.Instantiate(); player.SetMultiplayerAuthority((int)peerId); player.PeerId = (int)peerId; Players.AddChild(player); PlayerJoined?.Invoke(player); } void OnPeerDisconnected(long peerId) { var player = GetPlayerByPeerId((int)peerId); PlayerLeft?.Invoke(player); player.QueueFree(); } }