diff --git a/Assets/NetworkLobbyClient/Runtime/LobbyClient.dll b/Assets/NetworkLobbyClient/Runtime/LobbyClient.dll index f867f38..8956247 100644 Binary files a/Assets/NetworkLobbyClient/Runtime/LobbyClient.dll and b/Assets/NetworkLobbyClient/Runtime/LobbyClient.dll differ diff --git a/Assets/NetworkLobbyClient/Runtime/LobbyServerDto.dll b/Assets/NetworkLobbyClient/Runtime/LobbyServerDto.dll index 1646bfd..7b5acc4 100644 Binary files a/Assets/NetworkLobbyClient/Runtime/LobbyServerDto.dll and b/Assets/NetworkLobbyClient/Runtime/LobbyServerDto.dll differ diff --git a/LobbyClient/LobbyClient.cs b/LobbyClient/LobbyClient.cs index caf24bf..c5ed145 100644 --- a/LobbyClient/LobbyClient.cs +++ b/LobbyClient/LobbyClient.cs @@ -173,21 +173,23 @@ namespace Lobbies /// The lobby to request a nat punch for /// Optional password of lobby /// The port the game client will later use. We create a udp socket on it and send a packet to the lobby server to get the firewall to map that port for a short period of time - /// after that the udp client will be disposed - public void RequestLobbyNatPunch(Guid lobbyId, string? password, int port = 0) + /// after that the udp client will be disposed. + public int RequestLobbyNatPunch(Guid lobbyId, string? password, int port = 0) { + if(port < 0 && port > 65535) + throw new ArgumentOutOfRangeException(nameof(port)); + byte[]? passwordHash = null; if (!string.IsNullOrEmpty(password) && lobbyInformation.ContainsKey(lobbyId) && lobbyInformation[lobbyId].PasswordSalt != null) passwordHash = PasswordHash.Hash(password, lobbyInformation[lobbyId].PasswordSalt!); - Task.Run(() => - { - using (var udpEchoServer = new UdpEchoServer()) - { - udpEchoServer.Start(port); - QueryExternalIpAndPort(udpEchoServer.Send); - } + var udpEchoServer = new UdpEchoServer(); + udpEchoServer.Start(port); + Task.Run(() => + { + QueryExternalIpAndPort(udpEchoServer.Send); + udpEchoServer.Dispose(); var lobbyRequestNatPunch = new LobbyRequestNatPunch() { LobbyId = lobbyId, @@ -200,6 +202,8 @@ namespace Lobbies var len = lobbyRequestNatPunch.Serialize(messageData); _ = Task.Run(async () => { await tcpClient.Send(messageData, 0, len); bufferRental.Return(messageData); }); }); + + return udpEchoServer.Port; } public void UpdateLobby(string name, int gameMode, int maxPlayerCount, int playerCount, string? password, int port) @@ -381,6 +385,16 @@ namespace Lobbies { switch (LobbyMessageIdentifier.ReadLobbyMessageIdentifier(data.Span)) { + case LobbyNotFound.TypeId: + { + events.Enqueue(new LobbyClientEvent { EventType = LobbyClientEventTypes.LobbyJoinFailed, EventData = new LobbyJoinFailReason { Reason = LobbyJoinFailReason.FailReasons.LobbyNotFound, ErrorMessage = string.Empty } }); + } + break; + case LobbyWrongPassword.TypeId: + { + events.Enqueue(new LobbyClientEvent { EventType = LobbyClientEventTypes.LobbyJoinFailed, EventData = new LobbyJoinFailReason { Reason = LobbyJoinFailReason.FailReasons.WrongPassword, ErrorMessage = string.Empty } }); + } + break; case LobbyClientConnectionInfo.TypeId: { var lobbyClientConnectionInfo = LobbyClientConnectionInfo.Deserialize(data.Span); diff --git a/LobbyClient/LobbyClientEvent.cs b/LobbyClient/LobbyClientEvent.cs index 69f78f5..430631e 100644 --- a/LobbyClient/LobbyClientEvent.cs +++ b/LobbyClient/LobbyClientEvent.cs @@ -63,6 +63,10 @@ /// /// A direct connection test without a nat punch was testet. EventData is with information if a direct connection was possible and on what address. /// - DirectConnectionTestComplete + DirectConnectionTestComplete, + /// + /// A join request to a lobby has failed. EventData is with information about the failure. + /// + LobbyJoinFailed, } } diff --git a/LobbyClient/LobbyJoinFailReason.cs b/LobbyClient/LobbyJoinFailReason.cs new file mode 100644 index 0000000..f2b14c2 --- /dev/null +++ b/LobbyClient/LobbyJoinFailReason.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Lobbies +{ + public class LobbyJoinFailReason + { + public enum FailReasons + { + WrongPassword, + LobbyNotFound, + LobbyFull + } + + public FailReasons Reason { get; internal set; } + public string? ErrorMessage { get; internal set; } + } +} diff --git a/LobbyClient/UdpEchoServer.cs b/LobbyClient/UdpEchoServer.cs index b00d937..81020cf 100644 --- a/LobbyClient/UdpEchoServer.cs +++ b/LobbyClient/UdpEchoServer.cs @@ -198,6 +198,7 @@ namespace Lobbies if (!isDisposed) { Stop(); + while (isRunningV4 || isRunningV6) Task.Yield(); diff --git a/LobbyServer/Program.cs b/LobbyServer/Program.cs index 9aa1bb6..67fd490 100644 --- a/LobbyServer/Program.cs +++ b/LobbyServer/Program.cs @@ -243,6 +243,18 @@ tcpServer.DataReceived += (clientId, dataLength, data) => }); } } + else + { + var messageData = bufferRental.Rent(); + var lobbyNotFound = new LobbyNotFound() { LobbyId = lobbyRequestHostInfo.LobbyId }; + var messageDataLength = lobbyNotFound.Serialize(messageData); + _ = Task.Run(async () => { + await tcpServer.Send(clientId, messageData, 0, messageDataLength); + bufferRental.Return(messageData); + }); + + return; + } } } break; diff --git a/LobbyServerDto/LobbyNotFound.cs b/LobbyServerDto/LobbyNotFound.cs new file mode 100644 index 0000000..8682f7d --- /dev/null +++ b/LobbyServerDto/LobbyNotFound.cs @@ -0,0 +1,14 @@ +namespace LobbyServerDto +{ + /// + /// Send if a client requests information about a password protected lobby with an invalid password hash + /// + [LobbyMessage] + public partial class LobbyNotFound + { + /// + /// Id of the lobby + /// + public Guid LobbyId { get; set; } + } +} \ No newline at end of file