#nullable enable namespace Barotrauma.Networking; sealed class EosP2PSocket : P2PSocket { private readonly EosInterface.P2PSocket eosSocket; private EosP2PSocket( Callbacks callbacks, EosInterface.P2PSocket eosSocket, OwnerOrClient type) : base(callbacks, type) { this.eosSocket = eosSocket; } public static Result Create(Callbacks callbacks, OwnerOrClient type) { if (!EosInterface.Core.IsInitialized) { return Result.Failure(new Error(ErrorCode.EosNotInitialized)); } var eosSocketId = new EosInterface.SocketId { SocketName = EosP2PEndpoint.SocketName }; if (EosInterface.IdQueries.GetLoggedInPuids() is not { Length: > 0 } puids) { return Result.Failure(new Error(ErrorCode.EosNotLoggedIn)); } var socketCreateResult = EosInterface.P2PSocket.Create(puids[0], eosSocketId); if (!socketCreateResult.TryUnwrapSuccess(out var eosSocket)) { return Result.Failure(new Error(ErrorCode.FailedToCreateEosP2PSocket, socketCreateResult.ToString())); } var retVal = new EosP2PSocket(callbacks, eosSocket, type); eosSocket.HandleIncomingConnection.Register("Event".ToIdentifier(), retVal.OnIncomingConnection); eosSocket.HandleClosedConnection.Register("Event".ToIdentifier(), retVal.OnConnectionClosed); return Result.Success(retVal); } public override void ProcessIncomingMessages() { foreach (var msg in eosSocket.GetMessageBatch()) { EosP2PEndpoint endpoint = new EosP2PEndpoint(msg.Sender); callbacks.OnData(endpoint, new ReadWriteMessage(msg.Buffer, 0, msg.ByteLength * 8, false)); if (Type is OwnerOrClient.Owner) { dosProtection.OnPacket(endpoint); } } } public override bool SendMessage(P2PEndpoint endpoint, IWriteMessage outMsg, DeliveryMethod deliveryMethod) { if (endpoint is not EosP2PEndpoint { ProductUserId: var puid }) { return false; } var sendResult = eosSocket.SendMessage(new EosInterface.P2PSocket.OutgoingMessage( Buffer: outMsg.Buffer, ByteLength: outMsg.LengthBytes, Destination: puid, DeliveryMethod: deliveryMethod)); return sendResult.IsSuccess; } private void OnIncomingConnection(EosInterface.P2PSocket.IncomingConnectionRequest request) { var remoteEndpoint = new EosP2PEndpoint(request.RemoteUserId); if (callbacks.OnIncomingConnection(remoteEndpoint)) { request.Accept(); } } private void OnConnectionClosed(EosInterface.P2PSocket.RemoteConnectionClosed data) { var remoteEndpoint = new EosP2PEndpoint(data.RemoteUserId); var peerDisconnectPacket = PeerDisconnectPacket.WithReason(data.Reason switch { EosInterface.P2PSocket.RemoteConnectionClosed.ConnectionClosedReason.Unknown => DisconnectReason.Unknown, EosInterface.P2PSocket.RemoteConnectionClosed.ConnectionClosedReason.ClosedByLocalUser => DisconnectReason.Disconnected, EosInterface.P2PSocket.RemoteConnectionClosed.ConnectionClosedReason.ClosedByPeer => DisconnectReason.Disconnected, EosInterface.P2PSocket.RemoteConnectionClosed.ConnectionClosedReason.TimedOut => DisconnectReason.Timeout, EosInterface.P2PSocket.RemoteConnectionClosed.ConnectionClosedReason.TooManyConnections => DisconnectReason.ServerFull, EosInterface.P2PSocket.RemoteConnectionClosed.ConnectionClosedReason.InvalidMessage => DisconnectReason.Unknown, EosInterface.P2PSocket.RemoteConnectionClosed.ConnectionClosedReason.InvalidData => DisconnectReason.Unknown, EosInterface.P2PSocket.RemoteConnectionClosed.ConnectionClosedReason.ConnectionFailed => DisconnectReason.AuthenticationFailed, EosInterface.P2PSocket.RemoteConnectionClosed.ConnectionClosedReason.ConnectionClosed => DisconnectReason.Disconnected, EosInterface.P2PSocket.RemoteConnectionClosed.ConnectionClosedReason.NegotiationFailed => DisconnectReason.AuthenticationFailed, EosInterface.P2PSocket.RemoteConnectionClosed.ConnectionClosedReason.UnexpectedError => DisconnectReason.Unknown, EosInterface.P2PSocket.RemoteConnectionClosed.ConnectionClosedReason.Unhandled => DisconnectReason.Unknown, _ => DisconnectReason.Unknown }); callbacks.OnConnectionClosed(remoteEndpoint, peerDisconnectPacket); } public override void CloseConnection(P2PEndpoint endpoint) { if (endpoint is not EosP2PEndpoint { ProductUserId: var puid }) { return; } eosSocket.CloseConnection(puid); } public override void Dispose() { eosSocket.Dispose(); } }