Skip to content

Commit

Permalink
Targets multiple dotnet versions
Browse files Browse the repository at this point in the history
  • Loading branch information
BattlefieldDuck committed Jan 18, 2024
1 parent b34f2ed commit 55c4fc8
Show file tree
Hide file tree
Showing 31 changed files with 1,152 additions and 1,108 deletions.
9 changes: 5 additions & 4 deletions .github/workflows/dotnet-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,18 @@ on:
jobs:
build:

runs-on: ${{ matrix.os }}
runs-on: ubuntu-latest
strategy:
matrix:
os: [windows-latest]
dotnet: [ '6', '7', '8' ]

name: Dotnet ${{ matrix.dotnet }}
steps:
- uses: actions/checkout@v4
- name: Setup .NET 7
- name: Setup dotnet
uses: actions/setup-dotnet@v3
with:
dotnet-version: 7
dotnet-version: ${{ matrix.dotnet }}
- name: Install dependencies
run: dotnet restore OpenGSQ
- name: Build
Expand Down
5 changes: 4 additions & 1 deletion OpenGSQ/BinaryReaderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ public static bool IsEnd(this BinaryReader br)
/// <exception cref="IOException">An I/O error occurs.</exception>
public static string ReadStringEx(this BinaryReader br, byte[] charBytes)
{
charBytes ??= new byte[] { 0 };
if (charBytes == null)
{
charBytes = new byte[] { 0 };
}

var bytes = new List<byte>();
byte streamByte;
Expand Down
13 changes: 10 additions & 3 deletions OpenGSQ/OpenGSQ.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

<PropertyGroup>
<AssemblyTitle>OpenGSQ</AssemblyTitle>
<VersionPrefix>2.0.0</VersionPrefix>
<Version>2.0.0</Version>
<VersionPrefix>2.0.1</VersionPrefix>
<Version>2.0.1</Version>
<Authors>OpenGSQ, BattlefieldDuck</Authors>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.1;netstandard2.0;$(NetFrameworkMinimum)</TargetFrameworks>
<AssemblyName>OpenGSQ</AssemblyName>
<PackageId>OpenGSQ</PackageId>
<PackageIcon>icon.png</PackageIcon>
Expand All @@ -19,6 +19,13 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

<PropertyGroup>
<NetCoreAppCurrent>net8.0</NetCoreAppCurrent>
<NetCoreAppPrevious>net7.0</NetCoreAppPrevious>
<NetCoreAppMinimum>net6.0</NetCoreAppMinimum>
<NetFrameworkMinimum>net462</NetFrameworkMinimum>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="SharpZipLib" Version="1.4.2" />
<PackageReference Include="System.Net.Http.Json" Version="8.0.0" />
Expand Down
85 changes: 50 additions & 35 deletions OpenGSQ/ProtocolSocket.cs
Original file line number Diff line number Diff line change
@@ -1,46 +1,53 @@
using System;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;

namespace OpenGSQ
{
/// <summary>
/// A class that extends the UdpClient class with a Communicate method.
/// A class for handling UDP client communication.
/// </summary>
public static class UdpClientExtensions
public static class UdpClient
{
/// <summary>
/// Sends data to a connected UdpClient and returns the response.
/// </summary>
/// <param name="udpClient">The UdpClient to communicate with.</param>
/// <param name="protocolBase">The protocol information.</param>
/// <param name="data">The data to send.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the response data.</returns>
/// <exception cref="TimeoutException">Thrown when the operation times out.</exception>
public static async Task<byte[]> CommunicateAsync(this UdpClient udpClient, ProtocolBase protocolBase, byte[] data)
public static async Task<byte[]> CommunicateAsync(ProtocolBase protocolBase, byte[] data)
{
// Set the timeout
udpClient.Client.SendTimeout = protocolBase.Timeout;
udpClient.Client.ReceiveTimeout = protocolBase.Timeout;
using (var udpClient = new System.Net.Sockets.UdpClient())
{
// Set the timeout
udpClient.Client.SendTimeout = protocolBase.Timeout;
udpClient.Client.ReceiveTimeout = protocolBase.Timeout;

// Connect to the server
udpClient.Connect(protocolBase.Host, protocolBase.Port);
// Connect to the server
udpClient.Connect(protocolBase.Host, protocolBase.Port);

// Send the data
await udpClient.SendAsync(data, data.Length);
// Send the data
await udpClient.SendAsync(data, data.Length);

// Receive the data
return await udpClient.ReceiveAsyncWithTimeout();
// Receive the data
return await udpClient.ReceiveAsyncWithTimeout();
}
}
}

/// <summary>
/// A class that extends the UdpClient class with a Communicate method.
/// </summary>
public static class UdpClientExtensions
{
/// <summary>
/// Receives a UDP datagram asynchronously with a timeout.
/// </summary>
/// <param name="udpClient">The UdpClient to receive from.</param>
/// <returns>A byte array containing the received datagram.</returns>
/// <exception cref="TimeoutException">Thrown when the operation times out.</exception>
public static async Task<byte[]> ReceiveAsyncWithTimeout(this UdpClient udpClient)
public static async Task<byte[]> ReceiveAsyncWithTimeout(this System.Net.Sockets.UdpClient udpClient)
{
Task<UdpReceiveResult> receiveTask = udpClient.ReceiveAsync();

Expand All @@ -58,40 +65,48 @@ public static async Task<byte[]> ReceiveAsyncWithTimeout(this UdpClient udpClien
}

/// <summary>
/// A class that extends the TcpClient class with a Communicate method.
/// A class for handling TCP client communication.
/// </summary>
public static class TcpClientExtensions
public static class TcpClient
{
/// <summary>
/// Sends data to a connected TcpClient and returns the response.
/// </summary>
/// <param name="tcpClient">The TcpClient to communicate with.</param>
/// <param name="protocolBase">The protocol information.</param>
/// <param name="data">The data to send.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the response data.</returns>
/// <exception cref="TimeoutException">Thrown when the operation times out.</exception>
public static async Task<byte[]> CommunicateAsync(this TcpClient tcpClient, ProtocolBase protocolBase, byte[] data)
public static async Task<byte[]> CommunicateAsync(ProtocolBase protocolBase, byte[] data)
{
// Set the timeout
tcpClient.SendTimeout = protocolBase.Timeout;
tcpClient.ReceiveTimeout = protocolBase.Timeout;
using (var tcpClient = new System.Net.Sockets.TcpClient())
{
// Set the timeout
tcpClient.SendTimeout = protocolBase.Timeout;
tcpClient.ReceiveTimeout = protocolBase.Timeout;

// Connect to the server
await tcpClient.ConnectAsync(protocolBase.Host, protocolBase.Port);
// Connect to the server
await tcpClient.ConnectAsync(protocolBase.Host, protocolBase.Port);

// Send the data
await tcpClient.SendAsync(data);
// Send the data
await tcpClient.SendAsync(data);

return await tcpClient.ReceiveAsync();
return await tcpClient.ReceiveAsync();
}
}
}

/// <summary>
/// A class that extends the TcpClient class with a Communicate method.
/// </summary>
public static class TcpClientExtensions
{
/// <summary>
/// Sends data to a connected TcpClient.
/// </summary>
/// <param name="tcpClient">The TcpClient to send data to.</param>
/// <param name="data">The data to send.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
public static async Task SendAsync(this TcpClient tcpClient, byte[] data)
public static async Task SendAsync(this System.Net.Sockets.TcpClient tcpClient, byte[] data)
{
// Get the stream object for writing and reading
NetworkStream stream = tcpClient.GetStream();
Expand All @@ -106,20 +121,20 @@ public static async Task SendAsync(this TcpClient tcpClient, byte[] data)
/// <param name="tcpClient">The TcpClient to receive data from.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the received data.</returns>
/// <exception cref="TimeoutException">Thrown when the operation times out.</exception>
public static async Task<byte[]> ReceiveAsync(this TcpClient tcpClient)
public static async Task<byte[]> ReceiveAsync(this System.Net.Sockets.TcpClient tcpClient)
{
var cts = new CancellationTokenSource(tcpClient.Client.ReceiveTimeout);
var buffer = new byte[tcpClient.Client.ReceiveBufferSize];
var segment = new ArraySegment<byte>(buffer);
var receiveTask = tcpClient.Client.ReceiveAsync(segment, SocketFlags.None);

try
if (await Task.WhenAny(receiveTask, Task.Delay(tcpClient.Client.ReceiveTimeout)) == receiveTask)
{
var result = await tcpClient.Client.ReceiveAsync(segment, SocketFlags.None, cts.Token);
var receivedBytes = new byte[result];
Array.Copy(buffer, receivedBytes, result);
// Task completed within timeout.
var receivedBytes = new byte[receiveTask.Result];
Array.Copy(buffer, receivedBytes, receiveTask.Result);
return receivedBytes;
}
catch (OperationCanceledException)
else
{
// Task timed out.
throw new TimeoutException("The operation has timed out.");
Expand Down
48 changes: 24 additions & 24 deletions OpenGSQ/Protocols/ASE.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

Expand Down Expand Up @@ -35,33 +34,34 @@ public ASE(string host, int port, int timeout = 5000) : base(host, port, timeout
/// <returns>A dictionary containing the server status.</returns>
public async Task<Dictionary<string, object>> GetStatus()
{
using var udpClient = new UdpClient();
byte[] response = await udpClient.CommunicateAsync(this, _request);
byte[] header = response[..4];
byte[] response = await UdpClient.CommunicateAsync(this, _request);

if (!header.SequenceEqual(_response))
using (var br = new BinaryReader(new MemoryStream(response), Encoding.UTF8))
{
throw new InvalidPacketException($"Packet header mismatch. Received: {BitConverter.ToString(header)}. Expected: {BitConverter.ToString(_response)}.");
}

using var br = new BinaryReader(new MemoryStream(response[4..]), Encoding.UTF8);
byte[] header = br.ReadBytes(4);

var result = new Dictionary<string, object>
{
["gamename"] = ReadString(br),
["gameport"] = ReadString(br),
["hostname"] = ReadString(br),
["gametype"] = ReadString(br),
["map"] = ReadString(br),
["version"] = ReadString(br),
["password"] = ReadString(br),
["numplayers"] = ReadString(br),
["maxplayers"] = ReadString(br),
["rules"] = ParseRules(br),
["players"] = ParsePlayers(br)
};
if (!header.SequenceEqual(_response))
{
throw new InvalidPacketException($"Packet header mismatch. Received: {BitConverter.ToString(header)}. Expected: {BitConverter.ToString(_response)}.");
}

return result;
var result = new Dictionary<string, object>
{
["gamename"] = ReadString(br),
["gameport"] = ReadString(br),
["hostname"] = ReadString(br),
["gametype"] = ReadString(br),
["map"] = ReadString(br),
["version"] = ReadString(br),
["password"] = ReadString(br),
["numplayers"] = ReadString(br),
["maxplayers"] = ReadString(br),
["rules"] = ParseRules(br),
["players"] = ParsePlayers(br)
};

return result;
}
}

private Dictionary<string, string> ParseRules(BinaryReader br)
Expand Down
28 changes: 14 additions & 14 deletions OpenGSQ/Protocols/Battlefield.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Threading.Tasks;

namespace OpenGSQ.Protocols
Expand Down Expand Up @@ -141,22 +140,23 @@ public async Task<List<Dictionary<string, string>>> GetPlayers()

private async Task<List<string>> GetData(byte[] request)
{
using var tcpClient = new TcpClient();
byte[] response = await tcpClient.CommunicateAsync(this, request);
byte[] response = await TcpClient.CommunicateAsync(this, request);

var br = new BinaryReader(new MemoryStream(response));
br.ReadInt32(); // header
br.ReadInt32(); // packet length
var count = br.ReadInt32(); // string count
var data = new List<string>();

for (var i = 0; i < count; i++)
using (var br = new BinaryReader(new MemoryStream(response)))
{
br.ReadInt32(); // length of the string
data.Add(br.ReadStringEx());
}
br.ReadInt32(); // header
br.ReadInt32(); // packet length
var count = br.ReadInt32(); // string count
var data = new List<string>();

for (var i = 0; i < count; i++)
{
br.ReadInt32(); // length of the string
data.Add(br.ReadStringEx());
}

return data.GetRange(1, data.Count - 1);
return data.GetRange(1, data.Count - 1);
}
}
}
}
Loading

0 comments on commit 55c4fc8

Please sign in to comment.