Binary support

main
Thomas Woischnig 2023-12-01 22:58:44 +01:00
parent 840218f119
commit 97df572f1e
21 changed files with 310 additions and 45 deletions

View File

@ -0,0 +1,121 @@
{
"runtimeTarget": {
"name": ".NETStandard,Version=v2.1/",
"signature": ""
},
"compilationOptions": {},
"targets": {
".NETStandard,Version=v2.1": {},
".NETStandard,Version=v2.1/": {
"LobbyClient/1.0.0": {
"dependencies": {
"LobbyServerDto": "1.0.0"
},
"runtime": {
"LobbyClient.dll": {}
}
},
"System.Buffers/4.5.1": {
"runtime": {
"lib/netstandard2.0/System.Buffers.dll": {
"assemblyVersion": "4.0.3.0",
"fileVersion": "4.6.28619.1"
}
}
},
"System.ComponentModel.Annotations/5.0.0": {
"runtime": {
"lib/netstandard2.1/System.ComponentModel.Annotations.dll": {
"assemblyVersion": "5.0.0.0",
"fileVersion": "5.0.20.51904"
}
}
},
"System.Memory/4.5.5": {
"dependencies": {
"System.Buffers": "4.5.1",
"System.Numerics.Vectors": "4.4.0",
"System.Runtime.CompilerServices.Unsafe": "4.5.3"
},
"runtime": {
"lib/netstandard2.0/System.Memory.dll": {
"assemblyVersion": "4.0.1.2",
"fileVersion": "4.6.31308.1"
}
}
},
"System.Numerics.Vectors/4.4.0": {
"runtime": {
"lib/netstandard2.0/System.Numerics.Vectors.dll": {
"assemblyVersion": "4.1.3.0",
"fileVersion": "4.6.25519.3"
}
}
},
"System.Runtime.CompilerServices.Unsafe/4.5.3": {
"runtime": {
"lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll": {
"assemblyVersion": "4.0.4.1",
"fileVersion": "4.6.28619.1"
}
}
},
"LobbyServerDto/1.0.0": {
"dependencies": {
"System.ComponentModel.Annotations": "5.0.0",
"System.Memory": "4.5.5"
},
"runtime": {
"LobbyServerDto.dll": {}
}
}
}
},
"libraries": {
"LobbyClient/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"System.Buffers/4.5.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==",
"path": "system.buffers/4.5.1",
"hashPath": "system.buffers.4.5.1.nupkg.sha512"
},
"System.ComponentModel.Annotations/5.0.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-dMkqfy2el8A8/I76n2Hi1oBFEbG1SfxD2l5nhwXV3XjlnOmwxJlQbYpJH4W51odnU9sARCSAgv7S3CyAFMkpYg==",
"path": "system.componentmodel.annotations/5.0.0",
"hashPath": "system.componentmodel.annotations.5.0.0.nupkg.sha512"
},
"System.Memory/4.5.5": {
"type": "package",
"serviceable": true,
"sha512": "sha512-XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==",
"path": "system.memory/4.5.5",
"hashPath": "system.memory.4.5.5.nupkg.sha512"
},
"System.Numerics.Vectors/4.4.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-UiLzLW+Lw6HLed1Hcg+8jSRttrbuXv7DANVj0DkL9g6EnnzbL75EB7EWsw5uRbhxd/4YdG8li5XizGWepmG3PQ==",
"path": "system.numerics.vectors/4.4.0",
"hashPath": "system.numerics.vectors.4.4.0.nupkg.sha512"
},
"System.Runtime.CompilerServices.Unsafe/4.5.3": {
"type": "package",
"serviceable": true,
"sha512": "sha512-3TIsJhD1EiiT0w2CcDMN/iSSwnNnsrnbzeVHSKkaEgV85txMprmuO+Yq2AdSbeVGcg28pdNDTPK87tJhX7VFHw==",
"path": "system.runtime.compilerservices.unsafe/4.5.3",
"hashPath": "system.runtime.compilerservices.unsafe.4.5.3.nupkg.sha512"
},
"LobbyServerDto/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
}
}
}

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,23 @@
{
"name": "Unity.LobbyClient.Runtime",
"rootNamespace": "",
"references": [
],
"includePlatforms": [
"Android",
"iOS",
"LinuxStandalone64",
"CloudRendering",
"macOSStandalone",
"WindowsStandalone64"
],
"excludePlatforms": [],
"allowUnsafeCode": true,
"overrideReferences": true,
"precompiledReferences": [],
"autoReferenced": false,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@ -0,0 +1,17 @@
{
"name": "com.incobyte.lobbyclient",
"version": "1.0.0",
"displayName": "Game Lobby Client",
"description": "Provides a client for the game lobvy server to list and join lobbies",
"unity": "2022.3",
"keywords": [
"nat punch",
"lobby",
"network"
],
"author": {
"name": "Thomas Woischnig",
"email": "twoischnig@incobyte.de",
"url": "https://www.incobyte.de"
}
}

View File

@ -5,8 +5,6 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -20,6 +18,7 @@ namespace Lobbies
AutoResetEvent waitForExternalIp = new AutoResetEvent(false); AutoResetEvent waitForExternalIp = new AutoResetEvent(false);
private Dictionary<Guid, LobbyInfo> lobbyInformation = new Dictionary<Guid, LobbyInfo>();
private string? host; private string? host;
private int port; private int port;
private int connectionId; private int connectionId;
@ -74,8 +73,15 @@ namespace Lobbies
} }
} }
public void HostLobby(Guid gameId, string name, int gameMode, int maxPlayerCount,string? password, string? ip, int port) public void HostLobby(Guid gameId, string name, int gameMode, int maxPlayerCount, string? password, string? ip, int port)
{ {
byte[]? hash = null, salt = null;
if(!string.IsNullOrEmpty(password))
{
(hash, salt) = PasswordHash.Hash(password);
}
var lobbyCreate = new LobbyCreate() var lobbyCreate = new LobbyCreate()
{ {
GameId = gameId, GameId = gameId,
@ -83,7 +89,8 @@ namespace Lobbies
GameMode = gameMode, GameMode = gameMode,
MaxPlayerCount = maxPlayerCount, MaxPlayerCount = maxPlayerCount,
PlayerCount = 0, PlayerCount = 0,
PasswordHash = string.IsNullOrEmpty(password) ? null : SHA256.HashData(Encoding.UTF8.GetBytes(password)), PasswordHash = hash,
PasswordSalt = salt,
HostIp = ip, HostIp = ip,
HostPort = port HostPort = port
}; };
@ -95,10 +102,14 @@ namespace Lobbies
public void RequestLobbyHostInfo(Guid lobbyId, string? password) public void RequestLobbyHostInfo(Guid lobbyId, string? password)
{ {
byte[]? passwordHash = null;
if(!string.IsNullOrEmpty(password) && lobbyInformation.ContainsKey(lobbyId) && lobbyInformation[lobbyId].PasswordSalt != null)
passwordHash = PasswordHash.Hash(password, lobbyInformation[lobbyId].PasswordSalt!);
var lobbyCreate = new LobbyRequestHostInfo() var lobbyCreate = new LobbyRequestHostInfo()
{ {
LobbyId = lobbyId, LobbyId = lobbyId,
PasswordHash = string.IsNullOrEmpty(password) ? null : SHA256.HashData(Encoding.UTF8.GetBytes(password)), PasswordHash = passwordHash,
}; };
byte[] messageData = bufferRental.Rent(); byte[] messageData = bufferRental.Rent();
@ -110,13 +121,17 @@ namespace Lobbies
public delegate void SendUdpMessageCallback(IPEndPoint remoteEndpoint, byte[] messageBuffer, int messageLength); public delegate void SendUdpMessageCallback(IPEndPoint remoteEndpoint, byte[] messageBuffer, int messageLength);
public void RequestLobbyNatPunch(Guid lobbyId, string? password, SendUdpMessageCallback sendUdpCallback) public void RequestLobbyNatPunch(Guid lobbyId, string? password, SendUdpMessageCallback sendUdpCallback)
{ {
byte[]? passwordHash = null;
if (!string.IsNullOrEmpty(password) && lobbyInformation.ContainsKey(lobbyId) && lobbyInformation[lobbyId].PasswordSalt != null)
passwordHash = PasswordHash.Hash(password, lobbyInformation[lobbyId].PasswordSalt!);
Task.Run(() => Task.Run(() =>
{ {
QueryExternalIpAndPort(sendUdpCallback); QueryExternalIpAndPort(sendUdpCallback);
var lobbyRequestNatPunch = new LobbyRequestNatPunch() var lobbyRequestNatPunch = new LobbyRequestNatPunch()
{ {
LobbyId = lobbyId, LobbyId = lobbyId,
PasswordHash = string.IsNullOrEmpty(password) ? null : SHA256.HashData(Encoding.UTF8.GetBytes(password)), PasswordHash = passwordHash,
ClientIp = externalIp, ClientIp = externalIp,
ClientPort = externalPort ClientPort = externalPort
}; };
@ -129,13 +144,21 @@ namespace Lobbies
public void UpdateLobby(string name, int gameMode, int maxPlayerCount, int playerCount, string? password, string? ip, int port) public void UpdateLobby(string name, int gameMode, int maxPlayerCount, int playerCount, string? password, string? ip, int port)
{ {
byte[]? hash = null, salt = null;
if (!string.IsNullOrEmpty(password))
{
(hash, salt) = PasswordHash.Hash(password);
}
var lobbyUpdate = new LobbyUpdate() var lobbyUpdate = new LobbyUpdate()
{ {
Name = name, Name = name,
GameMode = gameMode, GameMode = gameMode,
MaxPlayerCount = maxPlayerCount, MaxPlayerCount = maxPlayerCount,
PlayerCount = playerCount, PlayerCount = playerCount,
PasswordHash = string.IsNullOrEmpty(password) ? null : SHA256.HashData(Encoding.UTF8.GetBytes(password)), PasswordHash = hash,
PasswordSalt = salt,
HostIp = ip, HostIp = ip,
HostPort = port HostPort = port
}; };
@ -277,6 +300,7 @@ namespace Lobbies
var lobbyInfo = LobbyInfo.Deserialize(data.Span); var lobbyInfo = LobbyInfo.Deserialize(data.Span);
if (lobbyInfo != null) if (lobbyInfo != null)
{ {
lobbyInformation[lobbyInfo.Id] = lobbyInfo;
events.Enqueue(new LobbyClientEvent { EventType = LobbyClientEventTypes.LobbyUpdate, EventData = lobbyInfo }); events.Enqueue(new LobbyClientEvent { EventType = LobbyClientEventTypes.LobbyUpdate, EventData = lobbyInfo });
} }
} }
@ -286,6 +310,7 @@ namespace Lobbies
var lobbyDelete = LobbyDelete.Deserialize(data.Span); var lobbyDelete = LobbyDelete.Deserialize(data.Span);
if (lobbyDelete != null) if (lobbyDelete != null)
{ {
lobbyInformation.Remove(lobbyDelete.Id);
events.Enqueue(new LobbyClientEvent { EventType = LobbyClientEventTypes.LobbyDelete, EventData = lobbyDelete }); events.Enqueue(new LobbyClientEvent { EventType = LobbyClientEventTypes.LobbyDelete, EventData = lobbyDelete });
} }
} }

View File

@ -1,13 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net7.0</TargetFramework> <TargetFramework>netstandard2.1</TargetFramework>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<OutputPath>..\Assets\NetworkLobbyClient\Runtime</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\LobbyServerDto\LobbyServerDto.csproj" /> <ProjectReference Include="..\LobbyServerDto\LobbyServerDto.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,37 @@

using System.Security.Cryptography;
namespace Lobbies
{
internal class PasswordHash
{
const int keySize = 64;
const int saltSize = 16;
const int iterations = 350000;
static HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA512;
static internal (byte[] hash, byte[] salt) Hash(string text)
{
using (var pbkdf2 = new Rfc2898DeriveBytes(
text,
saltSize,
iterations,
hashAlgorithm))
{
return (pbkdf2.GetBytes(keySize), pbkdf2.Salt);
}
}
static internal byte[] Hash(string text, byte[] salt)
{
using (var pbkdf2 = new Rfc2898DeriveBytes(
text,
salt,
iterations,
hashAlgorithm))
{
return pbkdf2.GetBytes(keySize);
}
}
}
}

View File

@ -29,9 +29,14 @@ namespace Lobbies
try try
{ {
cancellationTokenSource!.Token.ThrowIfCancellationRequested();
running = true; running = true;
tcpClient = new TcpClient(); tcpClient = new TcpClient();
await tcpClient.ConnectAsync(host, port, cancellationTokenSource!.Token); using (cancellationTokenSource!.Token.Register(() => { tcpClient.Close(); }))
{
await tcpClient.ConnectAsync(host, port);
}
networkStream = tcpClient.GetStream(); networkStream = tcpClient.GetStream();
Memory<byte> buffer = new byte[4096]; Memory<byte> buffer = new byte[4096];

View File

@ -9,6 +9,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\LobbyClient\LobbyClient.csproj" /> <ProjectReference Include="..\LobbyClient\LobbyClient.csproj" />
<ProjectReference Include="..\LobbyServerDto\LobbyServerDto.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -5,13 +5,13 @@ VisualStudioVersion = 17.7.34003.232
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LobbyServer", "LobbyServer\LobbyServer.csproj", "{64B89314-4185-4025-B8B9-AC0D3A921E6A}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LobbyServer", "LobbyServer\LobbyServer.csproj", "{64B89314-4185-4025-B8B9-AC0D3A921E6A}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LobbyServerDto", "LobbyServerDto\LobbyServerDto.csproj", "{5AA6CC31-3A59-4463-8E25-56852430765C}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LobbyClientTest", "LobbyClientTest\LobbyClientTest.csproj", "{2A5901FE-CE35-4C81-9B8A-E8180EAE7465}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LobbyServerSourceGenerator", "LobbyServerSourceGenerator\LobbyServerSourceGenerator.csproj", "{5353E418-2365-432B-ACC6-C20448F93CC9}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LobbyClient", "LobbyClient\LobbyClient.csproj", "{5BF63DAB-4D00-4A54-9881-43464732F6AD}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LobbyClient", "LobbyClient\LobbyClient.csproj", "{1D6DE49F-7A41-4117-A9AF-6EE3417948EB}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LobbyServerDto", "LobbyServerDto\LobbyServerDto.csproj", "{46E27B7A-A879-4493-BCA4-1994A367A637}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LobbyClientTest", "LobbyClientTest\LobbyClientTest.csproj", "{2A5901FE-CE35-4C81-9B8A-E8180EAE7465}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LobbyServerSourceGenerator", "LobbyServerSourceGenerator\LobbyServerSourceGenerator.csproj", "{04F95131-C7EF-410B-94E5-2D9162763155}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -23,22 +23,22 @@ Global
{64B89314-4185-4025-B8B9-AC0D3A921E6A}.Debug|Any CPU.Build.0 = Debug|Any CPU {64B89314-4185-4025-B8B9-AC0D3A921E6A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{64B89314-4185-4025-B8B9-AC0D3A921E6A}.Release|Any CPU.ActiveCfg = Release|Any CPU {64B89314-4185-4025-B8B9-AC0D3A921E6A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{64B89314-4185-4025-B8B9-AC0D3A921E6A}.Release|Any CPU.Build.0 = Release|Any CPU {64B89314-4185-4025-B8B9-AC0D3A921E6A}.Release|Any CPU.Build.0 = Release|Any CPU
{5AA6CC31-3A59-4463-8E25-56852430765C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5AA6CC31-3A59-4463-8E25-56852430765C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5AA6CC31-3A59-4463-8E25-56852430765C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5AA6CC31-3A59-4463-8E25-56852430765C}.Release|Any CPU.Build.0 = Release|Any CPU
{5353E418-2365-432B-ACC6-C20448F93CC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5353E418-2365-432B-ACC6-C20448F93CC9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5353E418-2365-432B-ACC6-C20448F93CC9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5353E418-2365-432B-ACC6-C20448F93CC9}.Release|Any CPU.Build.0 = Release|Any CPU
{1D6DE49F-7A41-4117-A9AF-6EE3417948EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1D6DE49F-7A41-4117-A9AF-6EE3417948EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1D6DE49F-7A41-4117-A9AF-6EE3417948EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1D6DE49F-7A41-4117-A9AF-6EE3417948EB}.Release|Any CPU.Build.0 = Release|Any CPU
{2A5901FE-CE35-4C81-9B8A-E8180EAE7465}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2A5901FE-CE35-4C81-9B8A-E8180EAE7465}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2A5901FE-CE35-4C81-9B8A-E8180EAE7465}.Debug|Any CPU.Build.0 = Debug|Any CPU {2A5901FE-CE35-4C81-9B8A-E8180EAE7465}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2A5901FE-CE35-4C81-9B8A-E8180EAE7465}.Release|Any CPU.ActiveCfg = Release|Any CPU {2A5901FE-CE35-4C81-9B8A-E8180EAE7465}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2A5901FE-CE35-4C81-9B8A-E8180EAE7465}.Release|Any CPU.Build.0 = Release|Any CPU {2A5901FE-CE35-4C81-9B8A-E8180EAE7465}.Release|Any CPU.Build.0 = Release|Any CPU
{5BF63DAB-4D00-4A54-9881-43464732F6AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5BF63DAB-4D00-4A54-9881-43464732F6AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5BF63DAB-4D00-4A54-9881-43464732F6AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5BF63DAB-4D00-4A54-9881-43464732F6AD}.Release|Any CPU.Build.0 = Release|Any CPU
{46E27B7A-A879-4493-BCA4-1994A367A637}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{46E27B7A-A879-4493-BCA4-1994A367A637}.Debug|Any CPU.Build.0 = Debug|Any CPU
{46E27B7A-A879-4493-BCA4-1994A367A637}.Release|Any CPU.ActiveCfg = Release|Any CPU
{46E27B7A-A879-4493-BCA4-1994A367A637}.Release|Any CPU.Build.0 = Release|Any CPU
{04F95131-C7EF-410B-94E5-2D9162763155}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{04F95131-C7EF-410B-94E5-2D9162763155}.Debug|Any CPU.Build.0 = Debug|Any CPU
{04F95131-C7EF-410B-94E5-2D9162763155}.Release|Any CPU.ActiveCfg = Release|Any CPU
{04F95131-C7EF-410B-94E5-2D9162763155}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -23,6 +23,7 @@ namespace LobbyServer
public int PlayerCount { get; set; } public int PlayerCount { get; set; }
public int MaxPlayerCount { get; set; } public int MaxPlayerCount { get; set; }
public byte[]? PasswordHash { get; set; } public byte[]? PasswordHash { get; set; }
public byte[]? PasswordSalt { get; set; }
public required string HostIp { get; set; } public required string HostIp { get; set; }
public int HostPort { get; set; } public int HostPort { get; set; }
} }

View File

@ -50,6 +50,7 @@ tcpServer.DataReceived += (clientId, dataLength, data) =>
PlayerCount = lobbyCreate.PlayerCount, PlayerCount = lobbyCreate.PlayerCount,
MaxPlayerCount = lobbyCreate.MaxPlayerCount, MaxPlayerCount = lobbyCreate.MaxPlayerCount,
PasswordHash = lobbyCreate.PasswordHash, PasswordHash = lobbyCreate.PasswordHash,
PasswordSalt = lobbyCreate.PasswordSalt,
HostClientId = clientId, HostClientId = clientId,
HostIp = lobbyCreate.HostIp == null ? tcpServer.GetClientIp(clientId)! : lobbyCreate.HostIp, HostIp = lobbyCreate.HostIp == null ? tcpServer.GetClientIp(clientId)! : lobbyCreate.HostIp,
HostPort = lobbyCreate.HostPort, HostPort = lobbyCreate.HostPort,
@ -110,6 +111,7 @@ tcpServer.DataReceived += (clientId, dataLength, data) =>
existingLobby.PlayerCount = lobbyUpdate.PlayerCount; existingLobby.PlayerCount = lobbyUpdate.PlayerCount;
existingLobby.MaxPlayerCount = lobbyUpdate.MaxPlayerCount; existingLobby.MaxPlayerCount = lobbyUpdate.MaxPlayerCount;
existingLobby.PasswordHash = lobbyUpdate.PasswordHash; existingLobby.PasswordHash = lobbyUpdate.PasswordHash;
existingLobby.PasswordSalt = lobbyUpdate.PasswordSalt;
if (lobbyUpdate.HostIp != null) if (lobbyUpdate.HostIp != null)
existingLobby.HostIp = lobbyUpdate.HostIp; existingLobby.HostIp = lobbyUpdate.HostIp;
@ -353,7 +355,8 @@ async Task SendLobbyUpdate(Lobby.LobbyUpdateType lobbyUpdateType, Lobby lobby)
GameMode = lobby.GameMode, GameMode = lobby.GameMode,
MaxPlayerCount = lobby.MaxPlayerCount, MaxPlayerCount = lobby.MaxPlayerCount,
PlayerCount = lobby.PlayerCount, PlayerCount = lobby.PlayerCount,
PasswordProtected = lobby.PasswordHash != null && lobby.PasswordHash.Length > 0 PasswordProtected = lobby.PasswordHash != null && lobby.PasswordHash.Length > 0,
PasswordSalt = lobby.PasswordSalt
}; };
messageDataLength = lobbyInfo.Serialize(messageData); messageDataLength = lobbyInfo.Serialize(messageData);
@ -401,7 +404,8 @@ async Task SendLobbiesToClient(int clientId, List<Lobby> lobbies)
GameMode = lobby.GameMode, GameMode = lobby.GameMode,
MaxPlayerCount = lobby.MaxPlayerCount, MaxPlayerCount = lobby.MaxPlayerCount,
PlayerCount = lobby.PlayerCount, PlayerCount = lobby.PlayerCount,
PasswordProtected = lobby.PasswordHash != null && lobby.PasswordHash.Length > 0 PasswordProtected = lobby.PasswordHash != null && lobby.PasswordHash.Length > 0,
PasswordSalt = lobby.PasswordSalt,
}; };
var messageDataLength = lobbyInfo.Serialize(messageData); var messageDataLength = lobbyInfo.Serialize(messageData);

View File

@ -33,9 +33,14 @@ namespace LobbyServerDto
/// <summary> /// <summary>
/// The hash of a password to protect the lobby. Only users with the password can request host information/nat punch. /// The hash of a password to protect the lobby. Only users with the password can request host information/nat punch.
/// </summary> /// </summary>
[MaxLength(26)] [MaxLength(64)]
public byte[]? PasswordHash { get; set; } public byte[]? PasswordHash { get; set; }
/// <summary> /// <summary>
/// The salt used to hash the password.
/// </summary>
[MaxLength(16)]
public byte[]? PasswordSalt { get; set; }
/// <summary>
/// The hosts ip. Used the the host information send to clients on their request. /// The hosts ip. Used the the host information send to clients on their request.
/// </summary> /// </summary>
[MaxLength(32)] [MaxLength(32)]

View File

@ -1,4 +1,6 @@
namespace LobbyServerDto using System.ComponentModel.DataAnnotations;
namespace LobbyServerDto
{ {
/// <summary> /// <summary>
/// Send when a lobby is created or updates, this contains the lobby information /// Send when a lobby is created or updates, this contains the lobby information
@ -30,5 +32,10 @@
/// True if the lobby requires a password to gain access /// True if the lobby requires a password to gain access
/// </summary> /// </summary>
public bool PasswordProtected { get; set; } public bool PasswordProtected { get; set; }
/// <summary>
/// The salt used to hash the password.
/// </summary>
[MaxLength(16)]
public byte[]? PasswordSalt { get; set; }
} }
} }

View File

@ -0,0 +1,7 @@
namespace LobbyServerDto
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, AllowMultiple = false, Inherited = false)]
public class LobbyMessageAttribute : Attribute
{
}
}

View File

@ -1,4 +1,6 @@
namespace LobbyServerDto using System;
namespace LobbyServerDto
{ {
/// <summary> /// <summary>
/// Used to read the message identifer from a received object /// Used to read the message identifer from a received object

View File

@ -3,12 +3,17 @@
<PropertyGroup> <PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<TargetFramework>net7.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>latest</LangVersion>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="System.Memory" Version="4.5.5" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\LobbyServerSourceGenerator\LobbyServerSourceGenerator.csproj" OutputItemType="Analyzer" /> <ProjectReference Include="..\LobbyServerSourceGenerator\LobbyServerSourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -29,6 +29,11 @@ namespace LobbyServerDto
/// </summary> /// </summary>
public byte[]? PasswordHash { get; set; } public byte[]? PasswordHash { get; set; }
/// <summary> /// <summary>
/// The salt used to hash the password.
/// </summary>
[MaxLength(16)]
public byte[]? PasswordSalt { get; set; }
/// <summary>
/// The hosts ip /// The hosts ip
/// </summary> /// </summary>
[MaxLength(32)] [MaxLength(32)]

View File

@ -158,7 +158,7 @@ using System.Text;
s.Append($@" s.Append($@"
if ({name} != null) if ({name} != null)
{{ {{
int maxLength = Math.Min(PasswordHash.Length, {maxLength}); int maxLength = Math.Min({name}.Length, {maxLength});
uint v = (uint)maxLength; uint v = (uint)maxLength;
while (v >= 0x80) while (v >= 0x80)
{{ {{
@ -167,7 +167,7 @@ using System.Text;
}} }}
buffer[offset++] = (byte)v; buffer[offset++] = (byte)v;
Buffer.BlockCopy(PasswordHash, 0, buffer, offset, maxLength); Buffer.BlockCopy({name}, 0, buffer, offset, maxLength);
offset += maxLength; offset += maxLength;
}} }}
else else
@ -237,7 +237,7 @@ using System.Text;
case "Guid": case "Guid":
s.Append($@" s.Append($@"
{{ {{
ret.{name} = new Guid(buffer.Slice(offset, 16)); ret.{name} = new Guid(buffer.Slice(offset, 16).ToArray());
offset+=16; offset+=16;
}}"); }}");
break; break;
@ -262,7 +262,7 @@ using System.Text;
if(strLen > 0) if(strLen > 0)
{{ {{
ret.{name} = Encoding.UTF8.GetString(buffer.Slice(offset, strLen)); ret.{name} = Encoding.UTF8.GetString(buffer.Slice(offset, strLen).ToArray());
offset += strLen; offset += strLen;
}} }}
}}"); }}");
@ -334,9 +334,4 @@ using System.Text;
return obj.Item1.GetHashCode(); return obj.Item1.GetHashCode();
} }
} }
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, AllowMultiple = false, Inherited = false)]
public class LobbyMessageAttribute : Attribute
{
}
} }

View File

@ -16,6 +16,10 @@
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.7.0" /> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.7.0" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Remove="bin\Release\netstandard2.0\\LobbyServerSourceGenerator.dll" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" /> <None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
</ItemGroup> </ItemGroup>