-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4442bc4
commit 66c8aa4
Showing
4 changed files
with
187 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
using System; | ||
using System.Threading.Tasks; | ||
using System.Linq; | ||
using System.IO; | ||
using System.Net.Sockets; | ||
using OpenGSQ.Responses.RakNet; | ||
|
||
namespace OpenGSQ.Protocols | ||
{ | ||
/// <summary> | ||
/// RakNet Protocol (https://wiki.vg/Raknet_Protocol) | ||
/// </summary> | ||
public class RakNet : ProtocolBase | ||
{ | ||
/// <inheritdoc/> | ||
public override string FullName => "RakNet Protocol"; | ||
|
||
private static readonly byte[] ID_UNCONNECTED_PING = { 0x01 }; | ||
private static readonly byte[] ID_UNCONNECTED_PONG = { 0x1C }; | ||
private static readonly byte[] TIMESTAMP = { 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89 }; | ||
private static readonly byte[] OFFLINE_MESSAGE_DATA_ID = { 0x00, 0xFF, 0xFF, 0x00, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, 0xFD, 0xFD, 0xFD, 0x12, 0x34, 0x56, 0x78 }; | ||
private static readonly byte[] CLIENT_GUID = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the RakNet class. | ||
/// </summary> | ||
/// <param name="host">The host.</param> | ||
/// <param name="port">The port.</param> | ||
/// <param name="timeout">The timeout. Default is 5000.</param> | ||
public RakNet(string host, int port, int timeout = 5000) : base(host, port, timeout) | ||
{ | ||
} | ||
|
||
/// <summary> | ||
/// Gets the server status asynchronously. | ||
/// </summary> | ||
/// <returns>A task that represents the asynchronous operation. The task result contains the server status.</returns> | ||
public async Task<StatusResponse> GetStatus() | ||
{ | ||
var request = ID_UNCONNECTED_PING.Concat(TIMESTAMP).Concat(OFFLINE_MESSAGE_DATA_ID).Concat(CLIENT_GUID).ToArray(); | ||
using var udpClient = new UdpClient(); | ||
var response = await udpClient.CommunicateAsync(this, request); | ||
|
||
using var br = new BinaryReader(new MemoryStream(response)); | ||
var header = br.ReadByte(); | ||
|
||
if (header != ID_UNCONNECTED_PONG[0]) | ||
{ | ||
throw new InvalidPacketException($"Packet header mismatch. Received: {header}. Expected: {ID_UNCONNECTED_PONG[0]}."); | ||
} | ||
|
||
br.ReadBytes(TIMESTAMP.Length + CLIENT_GUID.Length); // skip timestamp and guid | ||
var magic = br.ReadBytes(OFFLINE_MESSAGE_DATA_ID.Length); | ||
|
||
if (!magic.SequenceEqual(OFFLINE_MESSAGE_DATA_ID)) | ||
{ | ||
throw new InvalidPacketException($"Magic value mismatch. Received: {magic}. Expected: {OFFLINE_MESSAGE_DATA_ID}."); | ||
} | ||
|
||
br.ReadInt16(); // skip remaining packet length | ||
|
||
byte[] delimiter = { (byte)';' }; | ||
|
||
return new StatusResponse | ||
{ | ||
Edition = br.ReadStringEx(delimiter), | ||
MotdLine1 = br.ReadStringEx(delimiter), | ||
ProtocolVersion = int.Parse(br.ReadStringEx(delimiter)), | ||
VersionName = br.ReadStringEx(delimiter), | ||
NumPlayers = int.Parse(br.ReadStringEx(delimiter)), | ||
MaxPlayers = int.Parse(br.ReadStringEx(delimiter)), | ||
ServerUniqueId = br.ReadStringEx(delimiter), | ||
MotdLine2 = br.ReadStringEx(delimiter), | ||
GameMode = br.ReadStringEx(delimiter), | ||
GameModeNumeric = int.Parse(br.ReadStringEx(delimiter)), | ||
PortIPv4 = int.Parse(br.ReadStringEx(delimiter)), | ||
PortIPv6 = int.Parse(br.ReadStringEx(delimiter)) | ||
}; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
namespace OpenGSQ.Responses.RakNet | ||
{ | ||
/// <summary> | ||
/// Represents the status response from a Minecraft server. | ||
/// </summary> | ||
public class StatusResponse | ||
{ | ||
/// <summary> | ||
/// Gets or sets the edition of the server (MCPE or MCEE for Education Edition). | ||
/// </summary> | ||
public string Edition { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets the first line of the Message of the Day (MOTD). | ||
/// </summary> | ||
public string MotdLine1 { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets the protocol version of the server. | ||
/// </summary> | ||
public int ProtocolVersion { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets the version name of the server. | ||
/// </summary> | ||
public string VersionName { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets the number of players currently on the server. | ||
/// </summary> | ||
public int NumPlayers { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets the maximum number of players that can join the server. | ||
/// </summary> | ||
public int MaxPlayers { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets the unique ID of the server. | ||
/// </summary> | ||
public string ServerUniqueId { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets the second line of the Message of the Day (MOTD). | ||
/// </summary> | ||
public string MotdLine2 { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets the game mode of the server. | ||
/// </summary> | ||
public string GameMode { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets the numeric representation of the game mode. | ||
/// </summary> | ||
public int GameModeNumeric { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets the IPv4 port of the server. | ||
/// </summary> | ||
public int PortIPv4 { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets the IPv6 port of the server. | ||
/// </summary> | ||
public int PortIPv6 { get; set; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
using System.Threading.Tasks; | ||
using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
using OpenGSQTests; | ||
|
||
namespace OpenGSQ.Protocols.Tests | ||
{ | ||
[TestClass()] | ||
public class RakNetTests : TestBase | ||
{ | ||
// minecraftpe | ||
public RakNet raknet = new("mc.advancius.net", 19132); | ||
|
||
public RakNetTests() : base(nameof(RakNetTests)) | ||
{ | ||
_EnableSave = false; | ||
} | ||
|
||
[TestMethod()] | ||
public async Task GetStatusTest() | ||
{ | ||
SaveResult(nameof(GetStatusTest), await raknet.GetStatus()); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
{ | ||
"Edition": "MCPE", | ||
"MotdLine1": "Advancius Network", | ||
"ProtocolVersion": 630, | ||
"VersionName": "1.20.50", | ||
"NumPlayers": 147, | ||
"MaxPlayers": 400, | ||
"ServerUniqueId": "5341688303186863614", | ||
"MotdLine2": "discord.advancius.net", | ||
"GameMode": "Survival", | ||
"GameModeNumeric": 1, | ||
"PortIPv4": 19132, | ||
"PortIPv6": 0 | ||
} |