Minecraft protocol

Сетевой протокол Minecraft: Java Edition — бинарный, поверх TCP. Хорошо задокументирован на wiki.vg. Актуальная версия протокола на 2026 год — 775 (клиент 1.26.1). Числовые ID протоколов меняются с каждой версией: 1.20 = 763, 1.21 = 767, 1.21.5 = 770.

Формат пакета

┌─────────────────┬──────────────┬──────────────┐
│ Length (VarInt) │ ID (VarInt)  │ Data (bytes) │
└─────────────────┴──────────────┴──────────────┘

Состояния протокола

Соединение проходит через фазы, у каждой свой набор пакетов и один и тот же ID означает разные пакеты в разных фазах:

ФазаНачалоЧто происходит
HandshakeПервое подключениеКлиент шлёт 0x00 Handshake с версией протокола и «Next State»: 1 (Status) или 2 (Login)
StatusNext State = 1Server List Ping — клиент запрашивает JSON с motd/players/version. Здесь есть Ping/Pong для latency
LoginNext State = 2Обмен именами, аутентификация с Mojang/Microsoft, инициализация шифрования
ConfigurationПосле Login (с 1.20.2)Обмен ресурспаками, тегами реестра, brand-name сервера
PlayПосле ConfigurationИгровой процесс: движения, чат, мир, инвентарь

Server List Ping

Как майнкрафт-клиент показывает список серверов:

  1. TCP-подключение к server:25565.
  2. Клиент шлёт: Handshake (protocol=775, host="mc.example.com", port=25565, next_state=1).
  3. Клиент шлёт: Status Request (пустой пакет 0x00).
  4. Сервер отвечает: Status Response с JSON:
    {
      "version": {"name": "1.26.1", "protocol": 775},
      "players": {"max": 100, "online": 5, "sample": [...]},
      "description": {"text": "§aWelcome!"},
      "favicon": "data:image/png;base64,..."
    }
  5. Клиент шлёт Ping с payload (long timestamp), сервер эхо-ответом → latency.

Login и шифрование

  1. Клиент → Login Start: имя, UUID.
  2. Сервер → Encryption Request: RSA public key (1024 бита) + verify token (4 байта).
  3. Клиент генерирует случайный shared secret (16 байт для AES-128), шифрует RSA публичным ключом.
  4. Клиент шлёт зашифрованный shared secret + зашифрованный verify token в Encryption Response.
  5. Клиент делает POST на sessionserver.mojang.com/session/minecraft/join с SHA-1(server_id + shared_secret + public_key) — подтверждает аутентификацию.
  6. Сервер тоже проверяет через sessionserver.mojang.com/session/minecraft/hasJoined.
  7. Дальше AES/CFB8 с shared_secret — все пакеты зашифрованы.

Из-за AES/CFB8 (byte stream cipher) шифрование не блочное и не bloat'ит пакеты.

Компрессия

С определённого размера пакеты сжимаются zlib. Порог — Set Compression пакет с threshold (обычно 256 байт). Формат меняется на:

Length (VarInt) | Data Length (VarInt) | Compressed [ID + Data]

Если Data Length = 0 — пакет не сжат (был меньше threshold).

Типы данных

ТипРазмерИспользование
VarInt1-5 байтID пакетов, длины
VarLong1-10 байтПозиции блоков (до 1.13)
StringVarInt длина + UTF-8Имена, чаты
Position8 байтXZY упакованы в long (26+26+12 бит)
UUID16 байтИдентификаторы игроков и сущностей
NBTvaryNamed Binary Tag — метаданные предметов, миров
ChatString (JSON)Форматированный текст
Angle1 байтУгол 0-255 = 0-360°

Offline vs Online mode

Bedrock Edition

Bedrock (Windows 10 / Xbox / mobile) использует другой протоколRakNet поверх UDP. Несовместим с Java. Порт 19132/UDP. Есть прокси-серверы (Geyser) для мостов.

Query protocol

UDP-порт (по умолчанию тот же 25565) с отдельным протоколом чтобы узнать статус без TCP-подключения. Использует handshake + основной query с сессионным токеном. Стандартный ботам-мониторингам сервера.

См. также