Вверх ↑
Этот топик читают: Гость
Ответов: 247
Beta
лидер
#1: 2013-01-07 20:26:03 ЛС | профиль | цитата

Minecraft изнутри - статья 3, пакеты


Как я и обещал, продолжаем.


Сегодня мы разберем структуру пакетов и протокол авторизации.

Хотелось бы начать с аунтификации. В майнкрафте на данный момент есть две схемы - с поддержкой шифрования и без нее. Разберем обе.


С шифрованием

Схема





Без шифрования

Схема




Клиент может и не отправить пакет с ID 252, а сразу же 205, сервер просто проигнорирует и продолжит без шифрования. Стоить заметить, что при этом не отсылается запрос на сервера Minecraft.net

http://session.minecraft.net/game/joinserver.jsp?user=логин&sessionId=id_сессии&serverId=ключ_сервера
http://session.minecraft.net/game/checkserver.jsp?user=логин&serverId=ключ_сервера

Это же и не происходит при onlinemode=false

Классы для шифрования хранятся в пакете org.*. Когда я реализовывал свой флудер (и да, на гитхабе не самая рабочая версия, я ее выложил для демонстрации устройства сети), я поначалу тоже думал делать шифрование, но решил не реализовывать за ненадобностью.

Что же у нас происходит при авторизации? Для начала, сервер ждет от клиента Packet2Handshake, в котором передаются данные о сессии (логин и id). Далее сервер в любом случае присылает Packet253ServerAuthData с ключом сервера и кодом проверки, после чего клиент либо инициирует процесс активации шифрования, либо просто посылает пакет с ID 205 (Packet205ClientCommand), не реагируя на 253. Затем клиент получает пакет 1Login, в котором содержатся: ID его Entity, тип мира, текущее измерение, максимальное количество игроков, сложность и свой игровой режим (gamemode). Ладно, хватит занудного текста, перейдем к самим пакетам

Как же происходит отправка пакетов? Легко - все данные сваливаются в одну общую кучу в стандартный DataOutputStream. Сначала передаем ID пакета, а затем сами данные. Вот как это было реализовано у меня:

public void writePacket(Packet packet) throws IOException {

try {
this.sout.write(packet.getId());
packet.write(this.sout);
log.info("Write packet " + packet.getId());
} catch(Exception e) {
e.printStackTrace();
}
}

Хотелось бы рассказать о хитростях в плане отправки/чтения строк, массивов и всего прочего. Опять приведу свой код, так как я не стал реализовывать функции writeString и прочее.

public void write(DataOutputStream buf) throws IOException, NotSupportedOperationException {

buf.writeShort(message.length());
for(int i = 0; i ‹ message.length(); ++i) {
buf.writeChar(message.charAt(i));
}
}

передаем в функцию наш DataOutputStream и запихиваем данные.
Для передачи строки нам необходимо сначала передать ее длину, а затем каждый символ. При чтении делается тоже самое.

public static void writeString(String par0Str, DataOutputStream par1DataOutputStream) throws IOException

{
if (par0Str.length() › 32767)
{
throw new IOException("String too big");
}
else
{
par1DataOutputStream.writeShort(par0Str.length());
par1DataOutputStream.writeChars(par0Str);
}
}
public static void writeByteArray(DataOutputStream par0DataOutputStream, byte[] par1ArrayOfByte) throws IOException
{
par0DataOutputStream.writeShort(par1ArrayOfByte.length);
par0DataOutputStream.write(par1ArrayOfByte);
}
writeChars - стандартная функция, но цикл наглядней. Логика у них одна и та же.

Ну, подытожим. Авторизоваться можно и без шифрования, а можно и с ним. При отсылки массива байтов и строки мы отсылаем размер, а затем само содержимое.
В следующем посте мы создадим свой пакет и попробуем что-нибудь отправить, а пока на сегодня все.

901 специально для MCGL. При копировании указание копирайта обязательно.

карма: 0
0
Голосовали:TheHive, HydraLisk
Ответов: 1834
#2: 2013-01-07 20:26:57 ЛС | профиль | цитата
Хорош копировать с других сайтов и вставлять сюда.
карма: -25
0
Ответов: 247
Beta
лидер
#3: 2013-01-07 20:28:27 ЛС | профиль | цитата
TheHive, чего? Все статьи я пишу сам. Не веришь - поищи сам, эта статья только здесь
карма: 0
0
3
Сообщение
...