Search code examples
c#parsingtcpminecraftpacket

C# Getting a packet from a Minecraft server using tcp/ip


My main goal is to connect a C# client to a Minecraft server but i have some trouble to get content of the packet sended by the server. According to this page, a packet in Minecraft should match a specific format. ( Format of a packet )

Also, according to this, a string is prefixed by is length.

Here's the packet i'my trying to get.

Knowing these informations, here's my code :

  //S->C : Login Success
  int packet_Length = ReadVarInt(stream);
  int packet_Id = ReadVarInt(stream);


  int uuid_length = ReadVarInt(stream);
  string uuid = ReadString(stream, 16);

  int name_length = ReadVarInt(stream);
  string name = ReadString(stream, 16);


public static int ReadVarInt(Stream stream)
    {
        int value = 0;
        int length = 0;
        int currentByte;

        while (true)
        {
            currentByte = stream.ReadByte();
            value |= (currentByte & 0x7F) << (length++ * 7);
            if (length > 5) throw new IOException("VarInt too big");
            if ((currentByte & 0x80) != 0x80) break;
        }
        return value;
    }

 public static string ReadString(Stream stream, int length)
    {
        byte[] data = new byte[length];
        stream.Read(data);
        return Encoding.UTF8.GetString(data);
    }

And the result :

packet_Length : 3
packet_Id : 3
uuid : ↓☻►v9Q?►1??w??
name : 9♠mc_bot

The problem is that the packet ID should be 1, the uuid a regular string and the name only have "mc_bot" as value. I precise that the part who have to be done before work perfectly ( i think ) because the client join the server after getting the Login Success packet but i just can't get any data correctly.

Thanks !


Solution

  • So, with some help i finally found what was wrong with my process. I would like to point out that honestly, this type of error can be easily avoided by reading the documentation correctly, Which I didn't do...

    Here's my final code

                    int packet_Length = ReadVarInt(stream);
                    int packet_Id = ReadVarInt(stream);
    
                    Console.WriteLine($"packet_Length : {packet_Length}");
                    Console.WriteLine($"packet_Id : {packet_Id}");
    
                    //Enables compression. If compression is enabled,
                    //all following packets are encoded in the compressed packet format.
                    //Negative or zero values will disable compression,
                    //meaning the packet format should remain in the uncompressed packet format.
                    //However, this packet is entirely optional, and if not sent,
                    //compression will also not be enabled (the notchian server does not send the packet when compression is disabled).
                    if (packet_Id == 0x03)
                    {
                        //S->C : Set Compression (Optional)
                        int compression_threshold = ReadVarInt(stream);
                        Console.WriteLine($"packet_Id : {packet_Id}");
                    }
    
                    //S->C : Login Success
                    string uuid = ReadUUID(stream, 16);
                    int name_length = ReadVarInt(stream);
                    string name = ReadString(stream, name_length);
                    
                    Console.WriteLine($"uuid : {uuid}");
                    Console.WriteLine($"name_length : {name_length}");
                    Console.WriteLine($"name : {name}");
                    
    
        public static string ReadUUID(Stream stream, int length)
        {
            byte[] data = new byte[length];
    
            stream.Read(data);
    
            ulong b1 = BitConverter.ToUInt64(data,0);
            ulong b2 = BitConverter.ToUInt64(data,8);
    
    
            byte[] bytes = new byte[0];
            bytes = bytes.Concat(BitConverter.GetBytes(b1)).Concat(BitConverter.GetBytes(b2)).ToArray();
    
            string uuid = "";
            foreach (byte b in bytes)
                uuid += b.ToString("x2");
    
            return uuid.Substring(0, 8) + "-" + uuid.Substring(8, 4) + "-" + uuid.Substring(12, 4) + "-" + uuid.Substring(16, 4) + "-" + uuid.Substring(20, 12);
        }
    
    public static int ReadVarInt(Stream stream)
    {
        int value = 0;
        int length = 0;
        int currentByte;
    
        while (true)
        {
            currentByte = stream.ReadByte();
            value |= (currentByte & 0x7F) << (length++ * 7);
            if (length > 5) throw new IOException("VarInt too big");
            if ((currentByte & 0x80) != 0x80) break;
        }
        return value;
    }
    
    public static string ReadString(Stream stream, int length)
    {
        byte[] data = new byte[length];
        stream.Read(data);
        return Encoding.UTF8.GetString(data);
    }