Question

I'm trying to make client/bot for minecraft server to automatically guard chat and ban spammers. (first achievment)
I found some docs here and I've implemented data types from here (so they look like this - and I'm not finished yet). Now, I'm trying to send inital 0x02 packet, which should look like this:

My packet format

size    value                comment

1       0x02                 Packet ID
2+?     string               Username (I send "jakub")
2+?     another string       Server host name - here, the program FAILS*
4       25565                Port number

*Fails means that the bukkit server outputs following in the console, and the socket is closed:

11:09:45 [INFO] /127.0.0.1:51256 lost connection

I can see now way, how to test if my data types are correct, but because I seem to send username with no problem, I think I'm sending wrong information, though in correct format.

Generating string

But anyway, I'm curious if I did everything right. I have class for mc_short and mc_string. This is how mc_short creates 2 bytes of itself:

//mc_short::val is type of short 
void mc_short::asBytes(char* data) {  
    for (int i = 0; i < 2; i++)
       data[endianity?i:1-i] = (val >> (i * 8));  //Some magic with byteshifting.
       //endianity is set to false, because java uses BigEndian everywhere** (UNFRIENDLY PERSONS!!)
}

**Refer to http://wiki.vg/Data_Types:

All types in Java (and as such Minecraft) are big-endian, that is, the most significant byte comes first.

Then the string itself uses the mc_short and std::string to fill bytes in char*.

void mc_string::asBytes(char* data) {
    mc_short size((short)val.length());  //val is std::string
    size.endianity = endianity;          //mc_string::endianity is boolean, and is ony used to determine endianity of the first 2 bytes
    size.asBytes(data);  //Filling 2 bytes in data - length info
    for(short i=0; i<size.value(); i++) {
        data[i+2] = val[i];  //Copying std::string to data
    }
}

Question summary

  1. What should I send as "server hostname", the third field of 0x02?
  2. Am I sending the string correctly? Isn't there any other conversion required?

I'm aware, that my question is about not very known topic and thus you may not know nor the answer, nor the topic itself. Just ignore the question under such circumstances.

Was it helpful?

Solution

The strings are encoded in big-endian unicode (UTF-16, but big endian). You can't map your characters directly from memory if you aren't using Java (well, you can cheat if you just write a zero between each character and accept that it's a shitty way to do it). There's an example in C# of encoding Minecraft strings here.

As for the contents of that string, it should be the hostname to connect to. If Google ran a Minecraft server, that string might be minecraft.google.com.

An example of working with this actual packet is here.

So, with your question actually answered, some advice. The Minecraft protocol is terrible and writing a client will take a lot of work. You need to be able to support all packets in the protocol (yes, all of them), and you need to implement basic physics to fall to the ground so you don't get kicked for flying. There are several options, in order from best to worst choice:

  • Use Bukkit and write a plugin for this
  • Write a proxy instead of a client
  • Write a client, like you're trying to now

So, if you do the first, you'll need to write a plugin in Java. I don't know much about this.

I do know a lot about the latter two options. I'm the maintainer of Craft.Net, which is a bunch of libraries, including a generic networking library, and a client library. You could throw together a client or proxy in a few hours. An example client is in the same repo, and there's a proxy here. These all use C#.

If you still want to totally roll your own, good luck and godspeed.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top