feat: implement multiplayer session state management and add invalid port exception
This commit is contained in:
+3
-2
@@ -1,6 +1,7 @@
|
||||
namespace Game.Features.Multiplayer.Contracts.Exceptions;
|
||||
|
||||
/// <summary>
|
||||
/// Thrown when trying to host or join while already connected to a session.
|
||||
/// Thrown when trying to host or join while connecting or already connected to a session.
|
||||
/// </summary>
|
||||
public sealed class MultiplayerAlreadyConnectedException() : MultiplayerException("Already connected to a session.");
|
||||
public sealed class MultiplayerAlreadyConnectedException()
|
||||
: MultiplayerException("Already connected to or connecting with a session.");
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
namespace Game.Features.Multiplayer.Contracts.Exceptions;
|
||||
|
||||
public sealed class MultiplayerInvalidPortException(int port)
|
||||
: MultiplayerException($"Invalid port {port}. Port must be between 1 and 65535.");
|
||||
@@ -0,0 +1 @@
|
||||
uid://d3n8p5w2y7c4h
|
||||
@@ -8,8 +8,7 @@ public sealed class MultiplayerSession
|
||||
public const int MaxPlayers = 4;
|
||||
public IReadOnlyCollection<PeerId> PeerIds => _peerIds;
|
||||
public bool IsFull => _peerIds.Count >= MaxPlayers;
|
||||
public bool IsHosting { get; set; }
|
||||
public bool IsConnected { get; set; }
|
||||
public MultiplayerSessionState State { get; private set; } = MultiplayerSessionState.Disconnected;
|
||||
|
||||
private readonly HashSet<PeerId> _peerIds = [];
|
||||
|
||||
@@ -17,10 +16,25 @@ public sealed class MultiplayerSession
|
||||
|
||||
public void RemovePeer(PeerId peerId) => _peerIds.Remove(peerId);
|
||||
|
||||
public void StartHosting(PeerId hostPeerId)
|
||||
{
|
||||
_peerIds.Add(hostPeerId);
|
||||
State = MultiplayerSessionState.Hosting;
|
||||
}
|
||||
|
||||
public void StartConnecting()
|
||||
{
|
||||
State = MultiplayerSessionState.Connecting;
|
||||
}
|
||||
|
||||
public void MarkConnected()
|
||||
{
|
||||
State = MultiplayerSessionState.Connected;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_peerIds.Clear();
|
||||
IsHosting = false;
|
||||
IsConnected = false;
|
||||
State = MultiplayerSessionState.Disconnected;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Game.Features.Multiplayer.Domain;
|
||||
|
||||
public enum MultiplayerSessionState
|
||||
{
|
||||
Disconnected,
|
||||
Hosting,
|
||||
Connecting,
|
||||
Connected
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://b7m2q9r4v6x1k
|
||||
@@ -8,6 +8,9 @@ namespace Game.Features.Multiplayer.Godot;
|
||||
|
||||
public partial class MultiplayerController : Node, IMultiplayerPeer
|
||||
{
|
||||
private const int MinPort = 1;
|
||||
private const int MaxPort = 65535;
|
||||
|
||||
private readonly MultiplayerSession _session = new();
|
||||
private IMultiplayerPeerFactory _multiplayerPeerFactory;
|
||||
|
||||
@@ -33,29 +36,45 @@ public partial class MultiplayerController : Node, IMultiplayerPeer
|
||||
|
||||
private void OnConnectedToServer()
|
||||
{
|
||||
_session.MarkConnected();
|
||||
Connected?.Invoke();
|
||||
}
|
||||
|
||||
private void OnConnectionFailed()
|
||||
{
|
||||
_session.Reset();
|
||||
ResetConnection();
|
||||
ConnectionFailed?.Invoke();
|
||||
}
|
||||
|
||||
private void OnServerDisconnected()
|
||||
{
|
||||
_session.Reset();
|
||||
ResetConnection();
|
||||
Disconnected?.Invoke();
|
||||
}
|
||||
|
||||
private static void ValidatePort(int port)
|
||||
{
|
||||
if (port is < MinPort or > MaxPort)
|
||||
{
|
||||
throw new MultiplayerInvalidPortException(port);
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetConnection()
|
||||
{
|
||||
Multiplayer.MultiplayerPeer?.Close();
|
||||
Multiplayer.MultiplayerPeer = null;
|
||||
_session.Reset();
|
||||
}
|
||||
|
||||
private void AssertNoActiveSession()
|
||||
{
|
||||
if (_session.IsHosting)
|
||||
if (_session.State == MultiplayerSessionState.Hosting)
|
||||
{
|
||||
throw new MultiplayerAlreadyHostingException();
|
||||
}
|
||||
|
||||
if (_session.IsConnected)
|
||||
if (_session.State is MultiplayerSessionState.Connecting or MultiplayerSessionState.Connected)
|
||||
{
|
||||
throw new MultiplayerAlreadyConnectedException();
|
||||
}
|
||||
@@ -68,26 +87,25 @@ public partial class MultiplayerController : Node, IMultiplayerPeer
|
||||
|
||||
public void Host(int port)
|
||||
{
|
||||
ValidatePort(port);
|
||||
AssertNoActiveSession();
|
||||
|
||||
Multiplayer.MultiplayerPeer = _multiplayerPeerFactory.CreateHost(port, MultiplayerSession.MaxPlayers - 1);
|
||||
_session.AddPeer(new PeerId(Multiplayer.GetUniqueId()));
|
||||
_session.IsHosting = true;
|
||||
_session.StartHosting(new PeerId(Multiplayer.GetUniqueId()));
|
||||
}
|
||||
|
||||
public void Join(string address, int port)
|
||||
{
|
||||
ValidatePort(port);
|
||||
AssertNoActiveSession();
|
||||
|
||||
Multiplayer.MultiplayerPeer = _multiplayerPeerFactory.CreateClient(address, port);
|
||||
_session.IsConnected = true;
|
||||
_session.StartConnecting();
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
Multiplayer.MultiplayerPeer?.Close();
|
||||
Multiplayer.MultiplayerPeer = null;
|
||||
_session.Reset();
|
||||
ResetConnection();
|
||||
}
|
||||
|
||||
public override void _Ready()
|
||||
|
||||
Reference in New Issue
Block a user