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

View File

@ -1,13 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>netstandard2.1</TargetFramework>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<OutputPath>..\Assets\NetworkLobbyClient\Runtime</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\LobbyServerDto\LobbyServerDto.csproj" />
</ItemGroup>
</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
{
cancellationTokenSource!.Token.ThrowIfCancellationRequested();
running = true;
tcpClient = new TcpClient();
await tcpClient.ConnectAsync(host, port, cancellationTokenSource!.Token);
using (cancellationTokenSource!.Token.Register(() => { tcpClient.Close(); }))
{
await tcpClient.ConnectAsync(host, port);
}
networkStream = tcpClient.GetStream();
Memory<byte> buffer = new byte[4096];

View File

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

View File

@ -5,13 +5,13 @@ VisualStudioVersion = 17.7.34003.232
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LobbyServer", "LobbyServer\LobbyServer.csproj", "{64B89314-4185-4025-B8B9-AC0D3A921E6A}"
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
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
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
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
Global
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}.Release|Any CPU.ActiveCfg = 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.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.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
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

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

View File

@ -50,6 +50,7 @@ tcpServer.DataReceived += (clientId, dataLength, data) =>
PlayerCount = lobbyCreate.PlayerCount,
MaxPlayerCount = lobbyCreate.MaxPlayerCount,
PasswordHash = lobbyCreate.PasswordHash,
PasswordSalt = lobbyCreate.PasswordSalt,
HostClientId = clientId,
HostIp = lobbyCreate.HostIp == null ? tcpServer.GetClientIp(clientId)! : lobbyCreate.HostIp,
HostPort = lobbyCreate.HostPort,
@ -110,6 +111,7 @@ tcpServer.DataReceived += (clientId, dataLength, data) =>
existingLobby.PlayerCount = lobbyUpdate.PlayerCount;
existingLobby.MaxPlayerCount = lobbyUpdate.MaxPlayerCount;
existingLobby.PasswordHash = lobbyUpdate.PasswordHash;
existingLobby.PasswordSalt = lobbyUpdate.PasswordSalt;
if (lobbyUpdate.HostIp != null)
existingLobby.HostIp = lobbyUpdate.HostIp;
@ -353,7 +355,8 @@ async Task SendLobbyUpdate(Lobby.LobbyUpdateType lobbyUpdateType, Lobby lobby)
GameMode = lobby.GameMode,
MaxPlayerCount = lobby.MaxPlayerCount,
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);
@ -401,7 +404,8 @@ async Task SendLobbiesToClient(int clientId, List<Lobby> lobbies)
GameMode = lobby.GameMode,
MaxPlayerCount = lobby.MaxPlayerCount,
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);

View File

@ -33,9 +33,14 @@ namespace LobbyServerDto
/// <summary>
/// The hash of a password to protect the lobby. Only users with the password can request host information/nat punch.
/// </summary>
[MaxLength(26)]
[MaxLength(64)]
public byte[]? PasswordHash { get; set; }
/// <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.
/// </summary>
[MaxLength(32)]

View File

@ -1,4 +1,6 @@
namespace LobbyServerDto
using System.ComponentModel.DataAnnotations;
namespace LobbyServerDto
{
/// <summary>
/// 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
/// </summary>
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>
/// Used to read the message identifer from a received object

View File

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

View File

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

View File

@ -158,7 +158,7 @@ using System.Text;
s.Append($@"
if ({name} != null)
{{
int maxLength = Math.Min(PasswordHash.Length, {maxLength});
int maxLength = Math.Min({name}.Length, {maxLength});
uint v = (uint)maxLength;
while (v >= 0x80)
{{
@ -167,7 +167,7 @@ using System.Text;
}}
buffer[offset++] = (byte)v;
Buffer.BlockCopy(PasswordHash, 0, buffer, offset, maxLength);
Buffer.BlockCopy({name}, 0, buffer, offset, maxLength);
offset += maxLength;
}}
else
@ -237,7 +237,7 @@ using System.Text;
case "Guid":
s.Append($@"
{{
ret.{name} = new Guid(buffer.Slice(offset, 16));
ret.{name} = new Guid(buffer.Slice(offset, 16).ToArray());
offset+=16;
}}");
break;
@ -262,7 +262,7 @@ using System.Text;
if(strLen > 0)
{{
ret.{name} = Encoding.UTF8.GetString(buffer.Slice(offset, strLen));
ret.{name} = Encoding.UTF8.GetString(buffer.Slice(offset, strLen).ToArray());
offset += strLen;
}}
}}");
@ -334,9 +334,4 @@ using System.Text;
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" />
</ItemGroup>
<ItemGroup>
<None Remove="bin\Release\netstandard2.0\\LobbyServerSourceGenerator.dll" />
</ItemGroup>
<ItemGroup>
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
</ItemGroup>