Skip to content

Instantly share code, notes, and snippets.

@csh
Last active September 15, 2024 18:55
Show Gist options
  • Select an option

  • Save csh/2480d14fbbb33b4bbae3 to your computer and use it in GitHub Desktop.

Select an option

Save csh/2480d14fbbb33b4bbae3 to your computer and use it in GitHub Desktop.

Revisions

  1. csh revised this gist Oct 5, 2018. 1 changed file with 7 additions and 1 deletion.
    8 changes: 7 additions & 1 deletion ServerPing.cs
    Original file line number Diff line number Diff line change
    @@ -90,7 +90,13 @@ private static void Main(string[] args)
    */
    Flush(0);

    var buffer = new byte[4096];
    /*
    * If you are using a modded server then use a larger buffer to account,
    * see link for explanation and a motd to HTML snippet
    * https://gist.github.com/csh/2480d14fbbb33b4bbae3#gistcomment-2672658
    */
    var buffer = new byte[Int16.MaxValue];
    // var buffer = new byte[4096];
    _stream.Read(buffer, 0, buffer.Length);

    try
  2. Connor Spencer Harries renamed this gist Aug 12, 2015. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  3. Connor Spencer Harries revised this gist Aug 12, 2015. 1 changed file with 4 additions and 1 deletion.
    5 changes: 4 additions & 1 deletion Program.cs
    Original file line number Diff line number Diff line change
    @@ -1,12 +1,15 @@
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IO;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;
    using Newtonsoft.Json;

    #if DEBUG
    using System.Diagnostics;
    #endif

    namespace MCServerPing
    {
    class ServerPing
  4. Connor Spencer Harries revised this gist Jul 30, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Program.cs
    Original file line number Diff line number Diff line change
    @@ -296,7 +296,7 @@ class Player
    [JsonProperty(PropertyName = "name")]
    public string Name { get; set; }

    [JsonProperty(PropertyName = "version")]
    [JsonProperty(PropertyName = "id")]
    public string Id { get; set; }
    }
    #endregion
  5. Connor Spencer Harries revised this gist Apr 22, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Program.cs
    Original file line number Diff line number Diff line change
    @@ -46,7 +46,7 @@ private static void Main(string[] args)
    Console.Title = "Minecraft Server Ping";

    var client = new TcpClient();
    var task = client.ConnectAsync("hub.gammamc.net", 25565);
    var task = client.ConnectAsync("localhost", 25565);
    Console.WriteLine("Connecting to Minecraft server..");

    while (!task.IsCompleted)
  6. Connor Spencer Harries created this gist Apr 22, 2015.
    303 changes: 303 additions & 0 deletions Program.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,303 @@
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IO;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;
    using Newtonsoft.Json;

    namespace MCServerPing
    {
    class ServerPing
    {
    private static readonly Dictionary<char, ConsoleColor> Colours = new Dictionary<char, ConsoleColor>
    {
    { '0', ConsoleColor.Black },
    { '1', ConsoleColor.DarkBlue },
    { '2', ConsoleColor.DarkGreen },
    { '3', ConsoleColor.DarkCyan },
    { '4', ConsoleColor.DarkRed },
    { '5', ConsoleColor.DarkMagenta },
    { '6', ConsoleColor.Yellow },
    { '7', ConsoleColor.Gray },
    { '8', ConsoleColor.DarkGray },
    { '9', ConsoleColor.Blue },
    { 'a', ConsoleColor.Green },
    { 'b', ConsoleColor.Cyan },
    { 'c', ConsoleColor.Red },
    { 'd', ConsoleColor.Magenta },
    { 'e', ConsoleColor.Yellow },
    { 'f', ConsoleColor.White },
    { 'k', Console.ForegroundColor },
    { 'l', Console.ForegroundColor },
    { 'm', Console.ForegroundColor },
    { 'n', Console.ForegroundColor },
    { 'o', Console.ForegroundColor },
    { 'r', ConsoleColor.White }
    };

    private static NetworkStream _stream;
    private static List<byte> _buffer;
    private static int _offset;

    private static void Main(string[] args)
    {
    Console.Title = "Minecraft Server Ping";

    var client = new TcpClient();
    var task = client.ConnectAsync("hub.gammamc.net", 25565);
    Console.WriteLine("Connecting to Minecraft server..");

    while (!task.IsCompleted)
    {
    #if DEBUG
    Debug.WriteLine("Connecting..");
    #endif
    Thread.Sleep(250);
    }

    if (!client.Connected)
    {
    Console.ForegroundColor = ConsoleColor.Red;
    Console.WriteLine("Unable to connect to the server");
    Console.ResetColor();
    Console.ReadKey(true);
    Environment.Exit(1);
    }

    _buffer = new List<byte>();
    _stream = client.GetStream();
    Console.WriteLine("Sending status request");


    /*
    * Send a "Handshake" packet
    * http://wiki.vg/Server_List_Ping#Ping_Process
    */
    WriteVarInt(47);
    WriteString("localhost");
    WriteShort(25565);
    WriteVarInt(1);
    Flush(0);

    /*
    * Send a "Status Request" packet
    * http://wiki.vg/Server_List_Ping#Ping_Process
    */
    Flush(0);

    var buffer = new byte[4096];
    _stream.Read(buffer, 0, buffer.Length);

    try
    {
    var length = ReadVarInt(buffer);
    var packet = ReadVarInt(buffer);
    var jsonLength = ReadVarInt(buffer);
    #if DEBUG
    Console.WriteLine("Received packet 0x{0} with a length of {1}", packet.ToString("X2"), length);
    #endif
    var json = ReadString(buffer, jsonLength);
    var ping = JsonConvert.DeserializeObject<PingPayload>(json);

    Console.WriteLine("Software: {0}", ping.Version.Name);
    Console.WriteLine("Protocol: {0}", ping.Version.Protocol);
    Console.WriteLine("Players Online: {0}/{1}", ping.Players.Online, ping.Players.Max);
    WriteMotd(ping);

    Console.ReadKey(true);
    }
    catch (IOException ex)
    {
    /*
    * If an IOException is thrown then the server didn't
    * send us a VarInt or sent us an invalid one.
    */
    Console.ForegroundColor = ConsoleColor.Red;
    Console.WriteLine("Unable to read packet length from server,");
    Console.WriteLine("are you sure it's a Minecraft server?");
    #if DEBUG
    Console.WriteLine("Here are the details:");
    Console.WriteLine(ex.ToString());
    #endif
    Console.ResetColor();
    }
    }

    private static void WriteMotd(PingPayload ping)
    {
    Console.Write("Motd: ");
    var chars = ping.Motd.ToCharArray();
    for (var i = 0; i < ping.Motd.Length; i++)
    {
    try
    {
    if (chars[i] == '\u00A7' && Colours.ContainsKey(chars[i + 1]))
    {
    Console.ForegroundColor = Colours[chars[i + 1]];
    continue;
    }
    if (chars[i - 1] == '\u00A7' && Colours.ContainsKey(chars[i]))
    {
    continue;
    }
    }
    catch (IndexOutOfRangeException)
    {
    // End of string
    }
    Console.Write(chars[i]);
    }
    Console.WriteLine();
    Console.ResetColor();
    }

    #region Read/Write methods
    internal static byte ReadByte(byte[] buffer)
    {
    var b = buffer[_offset];
    _offset += 1;
    return b;
    }

    internal static byte[] Read(byte[] buffer, int length)
    {
    var data = new byte[length];
    Array.Copy(buffer, _offset, data, 0, length);
    _offset += length;
    return data;
    }

    internal static int ReadVarInt(byte[] buffer)
    {
    var value = 0;
    var size = 0;
    int b;
    while (((b = ReadByte(buffer)) & 0x80) == 0x80)
    {
    value |= (b & 0x7F) << (size++*7);
    if (size > 5)
    {
    throw new IOException("This VarInt is an imposter!");
    }
    }
    return value | ((b & 0x7F) << (size*7));
    }

    internal static string ReadString(byte[] buffer, int length)
    {
    var data = Read(buffer, length);
    return Encoding.UTF8.GetString(data);
    }

    internal static void WriteVarInt(int value)
    {
    while ((value & 128) != 0)
    {
    _buffer.Add((byte) (value & 127 | 128));
    value = (int) ((uint) value) >> 7;
    }
    _buffer.Add((byte) value);
    }

    internal static void WriteShort(short value)
    {
    _buffer.AddRange(BitConverter.GetBytes(value));
    }

    internal static void WriteString(string data)
    {
    var buffer = Encoding.UTF8.GetBytes(data);
    WriteVarInt(buffer.Length);
    _buffer.AddRange(buffer);
    }

    internal static void Write(byte b)
    {
    _stream.WriteByte(b);
    }

    internal static void Flush(int id = -1)
    {
    var buffer = _buffer.ToArray();
    _buffer.Clear();

    var add = 0;
    var packetData = new[] {(byte) 0x00};
    if (id >= 0)
    {
    WriteVarInt(id);
    packetData = _buffer.ToArray();
    add = packetData.Length;
    _buffer.Clear();
    }

    WriteVarInt(buffer.Length + add);
    var bufferLength = _buffer.ToArray();
    _buffer.Clear();

    _stream.Write(bufferLength, 0, bufferLength.Length);
    _stream.Write(packetData, 0, packetData.Length);
    _stream.Write(buffer, 0, buffer.Length);
    }
    #endregion
    }

    #region Server ping
    /// <summary>
    /// C# represenation of the following JSON file
    /// https://gist.github.com/thinkofdeath/6927216
    /// </summary>
    class PingPayload
    {
    /// <summary>
    /// Protocol that the server is using and the given name
    /// </summary>
    [JsonProperty(PropertyName = "version")]
    public VersionPayload Version { get; set; }

    [JsonProperty(PropertyName = "players")]
    public PlayersPayload Players { get; set; }

    [JsonProperty(PropertyName = "description")]
    public string Motd { get; set; }

    /// <summary>
    /// Server icon, important to note that it's encoded in base 64
    /// </summary>
    [JsonProperty(PropertyName = "favicon")]
    public string Icon { get; set; }
    }

    class VersionPayload
    {
    [JsonProperty(PropertyName = "protocol")]
    public int Protocol { get; set; }

    [JsonProperty(PropertyName = "name")]
    public string Name { get; set; }
    }

    class PlayersPayload
    {
    [JsonProperty(PropertyName = "max")]
    public int Max { get; set; }

    [JsonProperty(PropertyName = "online")]
    public int Online { get; set; }

    [JsonProperty(PropertyName = "sample")]
    public List<Player> Sample { get; set; }
    }

    class Player
    {
    [JsonProperty(PropertyName = "name")]
    public string Name { get; set; }

    [JsonProperty(PropertyName = "version")]
    public string Id { get; set; }
    }
    #endregion
    }