Files
Nitrox/NitroxClient/Communication/MultiplayerSession/MultiplayerSessionManager.cs
2025-07-06 00:23:46 +02:00

164 lines
6.4 KiB
C#

using System;
using System.Threading.Tasks;
using NitroxClient.Communication.Abstract;
using NitroxClient.Communication.MultiplayerSession.ConnectionState;
using NitroxClient.GameLogic;
using NitroxModel.DataStructures;
using NitroxModel.Helper;
using NitroxModel.MultiplayerSession;
using NitroxModel.Packets;
using NitroxModel.Serialization;
namespace NitroxClient.Communication.MultiplayerSession
{
public class MultiplayerSessionManager : IMultiplayerSession, IMultiplayerSessionConnectionContext
{
private static readonly Task initSerializerTask;
static MultiplayerSessionManager()
{
initSerializerTask = Task.Run(Packet.InitSerializer);
}
public IClient Client { get; }
public string IpAddress { get; private set; }
public int ServerPort { get; private set; }
public MultiplayerSessionPolicy SessionPolicy { get; private set; }
public PlayerSettings PlayerSettings { get; private set; }
public AuthenticationContext AuthenticationContext { get; private set; }
public IMultiplayerSessionConnectionState CurrentState { get; private set; }
public MultiplayerSessionReservation Reservation { get; private set; }
public MultiplayerSessionManager(IClient client)
{
Log.Info("Initializing MultiplayerSessionManager...");
Client = client;
CurrentState = new Disconnected();
}
// Testing entry point
internal MultiplayerSessionManager(IClient client, IMultiplayerSessionConnectionState initialState)
{
Client = client;
CurrentState = initialState;
}
public event MultiplayerSessionConnectionStateChangedEventHandler ConnectionStateChanged;
public async Task ConnectAsync(string ipAddress, int port)
{
IpAddress = ipAddress;
ServerPort = port;
await initSerializerTask;
await CurrentState.NegotiateReservationAsync(this);
}
public void ProcessSessionPolicy(MultiplayerSessionPolicy policy)
{
SessionPolicy = policy;
NitroxConsole.DisableConsole = SessionPolicy.DisableConsole;
Version localVersion = NitroxEnvironment.Version;
NitroxVersion nitroxVersion = new(localVersion.Major, localVersion.Minor);
switch (nitroxVersion.CompareTo(SessionPolicy.NitroxVersionAllowed))
{
case -1:
Log.Error($"Client is out of date. Server: {SessionPolicy.NitroxVersionAllowed}, Client: {localVersion}");
Log.InGame(Language.main.Get("Nitrox_OutOfDateClient")
.Replace("{serverVersion}", SessionPolicy.NitroxVersionAllowed.ToString())
.Replace("{localVersion}", localVersion.ToString()));
CurrentState.Disconnect(this);
return;
case 1:
Log.Error($"Server is out of date. Server: {SessionPolicy.NitroxVersionAllowed}, Client: {localVersion}");
Log.InGame(Language.main.Get("Nitrox_OutOfDateServer")
.Replace("{serverVersion}", SessionPolicy.NitroxVersionAllowed.ToString())
.Replace("{localVersion}", localVersion.ToString()));
CurrentState.Disconnect(this);
return;
}
CurrentState.NegotiateReservationAsync(this);
}
public void RequestSessionReservation(PlayerSettings playerSettings, AuthenticationContext authenticationContext)
{
// If a reservation has already been sent (in which case the client is enqueued in the join queue)
if (CurrentState.CurrentStage == MultiplayerSessionConnectionStage.AWAITING_SESSION_RESERVATION)
{
Log.Info("Waiting in join queue…");
Log.InGame(Language.main.Get("Nitrox_Waiting"));
return;
}
PlayerSettings = playerSettings;
AuthenticationContext = authenticationContext;
CurrentState.NegotiateReservationAsync(this);
}
public void ProcessReservationResponsePacket(MultiplayerSessionReservation reservation)
{
if (reservation.ReservationState == MultiplayerSessionReservationState.ENQUEUED_IN_JOIN_QUEUE)
{
Log.Info("Waiting in join queue…");
Log.InGame(Language.main.Get("Nitrox_Waiting"));
return;
}
Reservation = reservation;
CurrentState.NegotiateReservationAsync(this);
}
public void JoinSession()
{
CurrentState.JoinSession(this);
}
public void Disconnect()
{
if (CurrentState.CurrentStage != MultiplayerSessionConnectionStage.DISCONNECTED)
{
CurrentState.Disconnect(this);
}
}
public bool Send<T>(T packet) where T : Packet
{
if (!PacketSuppressor<T>.IsSuppressed)
{
Client.Send(packet);
return true;
}
return false;
}
public void UpdateConnectionState(IMultiplayerSessionConnectionState sessionConnectionState)
{
Validate.NotNull(sessionConnectionState);
string fromStage = CurrentState == null ? "null" : CurrentState.CurrentStage.ToString();
string username = AuthenticationContext == null ? "" : AuthenticationContext.Username;
Log.Debug($"Updating session stage from '{fromStage}' to '{sessionConnectionState.CurrentStage}' for '{username}'");
CurrentState = sessionConnectionState;
// Last connection state changed will not have any handlers
ConnectionStateChanged?.Invoke(CurrentState);
if (sessionConnectionState.CurrentStage == MultiplayerSessionConnectionStage.SESSION_RESERVED)
{
Log.PlayerName = username;
}
}
public void ClearSessionState()
{
IpAddress = null;
ServerPort = ServerList.DEFAULT_PORT;
SessionPolicy = null;
PlayerSettings = null;
AuthenticationContext = null;
Reservation = null;
}
}
}