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) │
└─────────────────┴──────────────┴──────────────┘
- Length — суммарная длина ID + Data в байтах, кодируется как VarInt.
- Packet ID — идентификатор пакета в текущем состоянии.
- Data — payload, формат зависит от типа пакета.
Состояния протокола
Соединение проходит через фазы, у каждой свой набор пакетов и один и тот же ID означает разные пакеты в разных фазах:
| Фаза | Начало | Что происходит |
|---|---|---|
| Handshake | Первое подключение | Клиент шлёт 0x00 Handshake с версией протокола и «Next State»: 1 (Status) или 2 (Login) |
| Status | Next State = 1 | Server List Ping — клиент запрашивает JSON с motd/players/version. Здесь есть Ping/Pong для latency |
| Login | Next State = 2 | Обмен именами, аутентификация с Mojang/Microsoft, инициализация шифрования |
| Configuration | После Login (с 1.20.2) | Обмен ресурспаками, тегами реестра, brand-name сервера |
| Play | После Configuration | Игровой процесс: движения, чат, мир, инвентарь |
Server List Ping
Как майнкрафт-клиент показывает список серверов:
- TCP-подключение к
server:25565. - Клиент шлёт:
Handshake(protocol=775, host="mc.example.com", port=25565, next_state=1). - Клиент шлёт:
Status Request(пустой пакет 0x00). - Сервер отвечает:
Status Responseс JSON:{ "version": {"name": "1.26.1", "protocol": 775}, "players": {"max": 100, "online": 5, "sample": [...]}, "description": {"text": "§aWelcome!"}, "favicon": "data:image/png;base64,..." } - Клиент шлёт
Pingс payload (long timestamp), сервер эхо-ответом → latency.
Login и шифрование
- Клиент →
Login Start: имя, UUID. - Сервер →
Encryption Request: RSA public key (1024 бита) + verify token (4 байта). - Клиент генерирует случайный shared secret (16 байт для AES-128), шифрует RSA публичным ключом.
- Клиент шлёт зашифрованный shared secret + зашифрованный verify token в
Encryption Response. - Клиент делает POST на
sessionserver.mojang.com/session/minecraft/joinс SHA-1(server_id + shared_secret + public_key) — подтверждает аутентификацию. - Сервер тоже проверяет через
sessionserver.mojang.com/session/minecraft/hasJoined. - Дальше 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).
Типы данных
| Тип | Размер | Использование |
|---|---|---|
| VarInt | 1-5 байт | ID пакетов, длины |
| VarLong | 1-10 байт | Позиции блоков (до 1.13) |
| String | VarInt длина + UTF-8 | Имена, чаты |
| Position | 8 байт | XZY упакованы в long (26+26+12 бит) |
| UUID | 16 байт | Идентификаторы игроков и сущностей |
| NBT | vary | Named Binary Tag — метаданные предметов, миров |
| Chat | String (JSON) | Форматированный текст |
| Angle | 1 байт | Угол 0-255 = 0-360° |
Offline vs Online mode
- Online mode — сервер проверяет аутентификацию через Mojang API. Игроки должны иметь настоящий аккаунт.
- Offline mode (
online-mode=false) — сервер не проверяет. Любой может подключиться с любым ником. UUID генерируется детерминированно от ника — legal-серые серверы часто используют для пиратов, но небезопасно (impersonation).
Bedrock Edition
Bedrock (Windows 10 / Xbox / mobile) использует другой протокол — RakNet поверх UDP. Несовместим с Java. Порт 19132/UDP. Есть прокси-серверы (Geyser) для мостов.
Query protocol
UDP-порт (по умолчанию тот же 25565) с отдельным протоколом чтобы узнать статус без TCP-подключения. Использует handshake + основной query с сессионным токеном. Стандартный ботам-мониторингам сервера.