diff --git a/README.MD b/README.MD new file mode 100644 index 0000000..b5d99a6 --- /dev/null +++ b/README.MD @@ -0,0 +1,16 @@ +# mc-protocol + +![version: 0.0](https://img.shields.io/badge/version-0.0-0a0.svg?style=flat) +![support protocol: 1.8](https://img.shields.io/badge/support_protocol-1.8-222.svg?style=flat) + +## Build + +```shell script +gradle build +``` + +### Build documentation + +```shell script +gradle sphinx +``` \ No newline at end of file diff --git a/src/docs/_static/server_info.schema.json b/src/docs/_static/server_info.schema.json new file mode 100644 index 0000000..62c0880 --- /dev/null +++ b/src/docs/_static/server_info.schema.json @@ -0,0 +1,137 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "version": { + "description": "Описание версии протокола", + "type": "object", + "properties": { + "name": { + "description": "Название версии", + "type": "string", + "examples": [ + "1.8.7" + ] + }, + "protocol": { + "description": "Номер версии", + "type": "number", + "examples": [ + 47 + ] + } + }, + "required": [ + "name", + "protocol" + ] + }, + "players": { + "description": "Информация о слотах и игроках", + "type": "object", + "properties": { + "max": { + "description": "Максимальное количество мест", + "type": "number", + "examples": [ + 20 + ] + }, + "online": { + "description": "Количество игроков на сервере", + "type": "number", + "examples": [ + 5 + ] + }, + "sample": { + "description": "Список некоторых игроков, что сейчас присутствуют на сервере", + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "description": "Имя игрока", + "type": "string", + "examples": [ + "Notch" + ] + }, + "id": { + "description": "UUID игрока", + "type": "string", + "pattern": "[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}", + "examples": [ + "00000000-0000-0000-0000-000000000000" + ] + } + }, + "required": [ + "name", + "id" + ] + } + } + }, + "required": [ + "max", + "online" + ] + }, + "description": { + "$id": "#/properties/description", + "description": "Описание сервера (motd)", + "type": [ + "object", + "string" + ], + "properties": { + "text": { + "type": "string" + }, + "bold": { + "type": ["boolean", "string"], + "pattern": "true|false" + }, + "italic": { + "type": ["boolean", "string"], + "pattern": "true|false" + }, + "underlined": { + "type": ["boolean", "string"], + "pattern": "true|false" + }, + "strikethrough": { + "type": ["boolean", "string"], + "pattern": "true|false" + }, + "obfuscated": { + "type": ["boolean", "string"], + "pattern": "true|false" + }, + "color": { + "type": "string", + "pattern": "(dark_)?(blue|green|aqua|red|gray)|(dark|light)_purple|black|gold|yellow|white|[klmnor]" + }, + "extra": { + "type": "array", + "items": { + "$ref": "#/properties/description" + } + } + }, + "required": [ + "text" + ] + }, + "favicon": { + "description": "Иконка сервера в формате base64", + "type": "string", + "pattern": "data:image/png;base64,.+" + } + }, + "required": [ + "version", + "players" + ] +} \ No newline at end of file diff --git a/src/docs/_static/style.css b/src/docs/_static/style.css new file mode 100644 index 0000000..9a9d498 --- /dev/null +++ b/src/docs/_static/style.css @@ -0,0 +1,30 @@ +/* https://stackoverflow.com/questions/23211695/modifying-content-width-of-the-sphinx-theme-read-the-docs */ +.wy-nav-content { + max-width: none; +} + +.wy-side-nav-search { + background-color: #ECD304; +} + +.wy-side-nav-search > a, .wy-side-nav-search .wy-dropdown > a { + color: #535252; +} + +.wy-side-nav-search > div.version { + color: rgba(0, 0, 0, 0.3); +} + +.rst-content .line-block { + margin-bottom: 0; +} + +.row-odd .line-block, +.row-even .line-block { + margin-bottom: 0; +} + +.row-odd th.head p, +.row-even th.head p { + margin-bottom: 0; +} \ No newline at end of file diff --git a/src/docs/_templates/layout.html b/src/docs/_templates/layout.html new file mode 100644 index 0000000..41f9d16 --- /dev/null +++ b/src/docs/_templates/layout.html @@ -0,0 +1,5 @@ + +{% extends "!layout.html" %} +{% block extrahead %} + +{% endblock %} \ No newline at end of file diff --git a/src/docs/conf.py b/src/docs/conf.py index a511937..cbe97ba 100644 --- a/src/docs/conf.py +++ b/src/docs/conf.py @@ -1,34 +1,34 @@ # -*- coding: utf-8 -*- -import sys, os -from recommonmark.parser import CommonMarkParser +import sphinx_rtd_theme +import os -project = u'My Project' -copyright = u'YYYY, John Doe' -version = '1.0' -release = '1.0.0' +project = u'mc-protocol' +copyright = u'2020, DmitriyMX' +version = '0.0' +release = '0.1.0' # General options -needs_sphinx = '1.0' -master_doc = 'index' -pygments_style = 'tango' -add_function_parentheses = True - -extensions = ['sphinx.ext.autodoc', 'sphinxcontrib.plantuml'] +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx_rtd_theme', + 'sphinxcontrib.plantuml', +] templates_path = ['_templates'] -exclude_trees = ['.build'] -source_suffix = ['.rst', '.md'] -source_encoding = 'utf-8-sig' -source_parsers = { - '.md': CommonMarkParser -} -# HTML options -html_theme = 'sphinx_rtd_theme' -html_short_title = "my-project" -htmlhelp_basename = 'my-project-doc' -html_use_index = True -html_show_sourcelink = False -html_static_path = ['_static'] +# Source options +source_encoding = 'utf-8-sig' +source_suffix = ['.rst'] # PlantUML options plantuml = os.getenv('plantuml') +plantuml_output_format = 'svg' + +# HTML options +html_theme = 'sphinx_rtd_theme' +html_use_index = True +html_show_sourcelink = False +html_static_path = ['_static'] +html_theme_options = { + 'collapse_navigation': False, + 'sticky_navigation': True +} \ No newline at end of file diff --git a/src/docs/data_types.rst b/src/docs/data_types.rst new file mode 100644 index 0000000..c6d3835 --- /dev/null +++ b/src/docs/data_types.rst @@ -0,0 +1,61 @@ +Типы данных +=========== + ++----------------+-------------------+-----------------------------------------------------+--------------------------------------------------------------------------------+ +| Тип | Размер (в байтах) | Кодирование | Коментарий | ++================+===================+=====================================================+================================================================================+ +| Boolean | 1 | True или False | True = ``0x01``; False = ``0x00`` | ++----------------+-------------------+-----------------------------------------------------+--------------------------------------------------------------------------------+ +| Byte | 1 | Число от -128 до 127 | 8-bit число со знаком | ++----------------+-------------------+-----------------------------------------------------+--------------------------------------------------------------------------------+ +| Unsigned Byte | 1 | Число от 0 до 255 | 8-bit без знаковое число | ++----------------+-------------------+-----------------------------------------------------+--------------------------------------------------------------------------------+ +| Short | 2 | Число от -32768 до 32767 | 16-bit число со знаком | ++----------------+-------------------+-----------------------------------------------------+--------------------------------------------------------------------------------+ +| Unsigned Short | 2 | Число от 0 до 65535 | 16-bit без знаковое число | ++----------------+-------------------+-----------------------------------------------------+--------------------------------------------------------------------------------+ +| Int | 4 | Число от -2147483648 и 2147483647 | 32-bit число со знаком | ++----------------+-------------------+-----------------------------------------------------+--------------------------------------------------------------------------------+ +| Long | 8 | Число от -9223372036854775808 и 9223372036854775807 | 64-bit число со знаком | ++----------------+-------------------+-----------------------------------------------------+--------------------------------------------------------------------------------+ +| Float | 4 | 32-bit число одинарной точности (IEEE 754-2008) | |Single-precision floating-point format| | ++----------------+-------------------+-----------------------------------------------------+--------------------------------------------------------------------------------+ +| Double | 8 | 64-bit число одинарной точности (IEEE 754-2008) | |Double-precision floating-point format| | ++----------------+-------------------+-----------------------------------------------------+--------------------------------------------------------------------------------+ +| String (n) | | >= 1 | Последовательность Unicode scalar values | | В начале пишется длина строки в **VarInt**, после чего записываются символы. | +| | | <= (n * 4) + 3 | | | Каждый символ может состоять |максимум из 4 байт|. | +| | | | | Максимальная длина строки - 32767 (``3`` в колонке Размер - это как раз | +| | | | размер **VarInt** для этого числа). | ++----------------+-------------------+-----------------------------------------------------+--------------------------------------------------------------------------------+ +| Text | | >= 1 | JSON, закодированный как String | |wiki.vg:Chat| | +| | | <= (n * 4) + 3 | | | ++----------------+-------------------+-----------------------------------------------------+--------------------------------------------------------------------------------+ +| VarInt | | >= 1 | Число от -2147483648 и 2147483647 | 32-bit число с плавающей размерностью от 1 до 5 байт | +| | | <= 5 | | | ++----------------+-------------------+-----------------------------------------------------+--------------------------------------------------------------------------------+ +| VarLong | | >= 1 | Число от -9223372036854775808 и 9223372036854775807 | 64-bit число с плавающей размерностью от 1 до 10 байт | +| | | <= 10 | | | ++----------------+-------------------+-----------------------------------------------------+--------------------------------------------------------------------------------+ + + + + +.. |Single-precision floating-point format| raw:: html + + Single-precision floating-point format + +.. |Double-precision floating-point format| raw:: html + + Double-precision floating-point format + +.. |максимум из 4 байт| raw:: html + + максимум из 4 байт + +.. |wiki.vg:Chat| raw:: html + + wiki.vg:Chat + +.. |wiki.vg:Data types| raw:: html + + wiki.vg:Data types \ No newline at end of file diff --git a/src/docs/index.rst b/src/docs/index.rst index 37229ba..dc460b7 100644 --- a/src/docs/index.rst +++ b/src/docs/index.rst @@ -1,27 +1,10 @@ -Это заголовок -============= -Заголовок содержит главную тему и отделяется символами '='. -Их количество должно быть не меньше, чем количество символов -в заголовке. +Сетевой протокол Minecraft 1.8 +============================== -Подзаголовок ------------- -Подзаголовки отделяются символами '-'. Их количество должно -быть тем же, что и количество символов в подзаголовке -(так же, как и в случае с заголовками). +.. toctree:: + :maxdepth: 4 -Списки могут быть маркированными: - - * Элемент Foo - * Элемент Bar - -Или же автоматически пронумерованными: - - #. Элемент 1 - #. Элемент 2 - -Внутренняя разметка -------------––––––- -Слова можно выделять *наклонным* или **полужирным** шрифтами. -Фрагменты кода (например, примеры команд) можно заключать в обратные кавычки, например: -команда ``sudo`` дает вам привилегии суперпользователя! + data_types + packet_format + packets + protocol_schema \ No newline at end of file diff --git a/src/docs/packet_format.rst b/src/docs/packet_format.rst new file mode 100644 index 0000000..62f7d22 --- /dev/null +++ b/src/docs/packet_format.rst @@ -0,0 +1,39 @@ +Формат пакетов +============== + ++-------------+--------+----------------------------------------------------------------+ +| Название | Тип | Коментарии | ++=============+========+================================================================+ +| SIZE | VarInt | | Общий размер пакета в байтах. | +| | | | Вычисляется как: ``sizeOf(packet_id) + sizeOf(packet_data)`` | ++-------------+--------+----------------------------------------------------------------+ +| PACKET ID | VarInt | Идентификатор пакета | ++-------------+--------+----------------------------------------------------------------+ +| PACKET DATA | bytes | Данные/Полезная нагрузка | ++-------------+--------+----------------------------------------------------------------+ + + +Пример +------ + +Пакет **DisconnectPacket** + +.. code-block:: none + + +-------------------------------------------------+ + | 0 1 2 3 4 5 6 7 8 9 a b c d e f | + +--------+-------------------------------------------------+----------------+ + |00000000| 2c 00 2a 22 59 6f 75 20 61 72 65 20 6e 6f 74 20 |,.*"You are not | + |00000010| 77 68 69 74 65 2d 6c 69 73 74 65 64 20 6f 6e 20 |white-listed on | + |00000020| 74 68 69 73 20 73 65 72 76 65 72 21 22 |this server!" | + +--------+-------------------------------------------------+----------------+ + ++-------------+-----------+--------------------------------------------------------------+ +| SIZE | PACKET ID | PACKET DATA | +| | +--------------------------------------------------------------+ +| | | Поле: Reason (тип **Text** в виде **String**) | +| | +----------------------------+---------------------------------+ +| | | Длинна строки (**VarInt**) | Сама *"строка"* | ++-------------+-----------+----------------------------+---------------------------------+ +| ``2c`` = 44 | ``00`` | ``2a`` = 42 | ``22 59 6f 75 ... 65 72 21 22`` | ++-------------+-----------+----------------------------+---------------------------------+ diff --git a/src/docs/packets.rst b/src/docs/packets.rst new file mode 100644 index 0000000..9588557 --- /dev/null +++ b/src/docs/packets.rst @@ -0,0 +1,7 @@ +Список пакетов +============== + +.. toctree:: + + packets_clientside + packets_serverside \ No newline at end of file diff --git a/src/docs/packets_clientside.rst b/src/docs/packets_clientside.rst new file mode 100644 index 0000000..7d58d6b --- /dev/null +++ b/src/docs/packets_clientside.rst @@ -0,0 +1,58 @@ +От Клиента к Серверу +==================== + +HANDSHAKING +----------- + +HandshakePacket +^^^^^^^^^^^^^^^ + +Основная задача пакета: указать серверу на какой **State** нужно переключиться. + ++------------------+----------------+----------------------------------------------+ +| Поле | Тип | Коментарий | ++==================+================+==============================================+ +| Protocol version | VarInt | |Версия протокола| | ++------------------+----------------+----------------------------------------------+ +| Server address | Stirng | Hostname или IP | ++------------------+----------------+----------------------------------------------+ +| Server port | Unsigned Short | Порт сервера | ++------------------+----------------+----------------------------------------------+ +| Next stage | VarInt | ID State на который необходимо переключиться | ++------------------+----------------+----------------------------------------------+ + +STATUS +------ + +StatusServerRequest +^^^^^^^^^^^^^^^^^^^ + +Запрос информации о сервере. +Пакет не содержит никаких данных. + +PingPacket +^^^^^^^^^^ + +| Формат точно такой же как и у :ref:`PingPacket от Сервера к Клиенту `. +| Клиент должен вернуть Серверу данный пакет "как есть", без изменений. + +LOGIN +----- + +LoginStartPacket +^^^^^^^^^^^^^^^^ + +Запуск авторизации. + ++------+--------+------------------+ +| Поле | Тип | Коментарий | ++======+========+==================+ +| Name | String | Имя/Логин игрока | ++------+--------+------------------+ + + + + +.. |Версия протокола| raw:: html + + Версия протокола \ No newline at end of file diff --git a/src/docs/packets_serverside.rst b/src/docs/packets_serverside.rst new file mode 100644 index 0000000..bb3c69f --- /dev/null +++ b/src/docs/packets_serverside.rst @@ -0,0 +1,75 @@ +От Сервера к Клиенту +==================== + +STATUS +------ + +StatusServerResponse +^^^^^^^^^^^^^^^^^^^^ + +Информация о Сервере. + ++-------------+--------+-------------------------------------+ +| Поле | Тип | Коментарий | ++=============+========+=====================================+ +| Server info | String | Информация о сервере в JSON формате | ++-------------+--------+-------------------------------------+ + +В поле *Server info* находится JSON объект следующего вида: + +.. code-block:: json + + { + "version": { + "name": "1.8.7", + "protocol": 47 + }, + "players": { + "max": 20, + "online": 5, + "sample": [ + { + "name": "Notch", + "id": "00000000-0000-0000-0000-000000000000" + } + ] + }, + "description": { + "text": "Hello world" + }, + "favicon": "data:image/png;base64," + } + +Подробнее: :download:`JSON Schema <_static/server_info.schema.json>` + +PingPacket +^^^^^^^^^^ +.. _serverside_pingpacket: + +Пакет для обмена "пингом". + ++---------+------+-------------+ +| Поле | Тип | Коментарий | ++=========+======+=============+ +| Payload | Long | Любое число | ++---------+------+-------------+ + +.. note:: + + | "Ванильный" сервер в *Payload* указывает текущее время в формате unixstamp. + | Но по факту в данное поле можно указать любое число: клиент всё равно обязан вернуть данный пакет "как есть". + + +LOGIN +----- + +DisconnectPacket +^^^^^^^^^^^^^^^^ + +Отключение клиента сервером с указанием причины. + ++--------+------+----------------------------------+ +| Поле | Тип | Коментарий | ++========+======+==================================+ +| Reason | Text | Причина отключения. Опционально. | ++--------+------+----------------------------------+ diff --git a/src/docs/protocol_schema.rst b/src/docs/protocol_schema.rst new file mode 100644 index 0000000..928b79f --- /dev/null +++ b/src/docs/protocol_schema.rst @@ -0,0 +1,29 @@ +Схемы работы протокола +====================== + +Получение информации о Сервере +------------------------------ + +.. uml:: + + CLIENT --\ SERVER: Подключение + CLIENT -> SERVER: **HandshakePacket** с указанием "Next state" = STATUS + CLIENT -> SERVER: **StatusServerRequest** + CLIENT <- SERVER: **StatusServerResponse** + CLIENT -> SERVER: **PingPacket** (ping) + CLIENT <- SERVER: **PingPacket** (pong) + CLIENT \-- SERVER: Разрыв соединения + +Вход на сервер +-------------- + +Неудачный вход / Доступ закрыт +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. uml:: + + CLIENT --\ SERVER: Подключение + CLIENT -> SERVER: **HandshakePacket** с указанием "Next state" = LOGIN + CLIENT -> SERVER: **LoginStartPacket** + CLIENT <- SERVER: **DisconnectPacket** + CLIENT \-- SERVER: Разрыв соединения \ No newline at end of file diff --git a/src/main/java/mc/protocol/handshake/client/HandshakePacket.java b/src/main/java/mc/protocol/handshake/client/HandshakePacket.java index 7a70ba2..c79d785 100644 --- a/src/main/java/mc/protocol/handshake/client/HandshakePacket.java +++ b/src/main/java/mc/protocol/handshake/client/HandshakePacket.java @@ -11,7 +11,7 @@ import mc.protocol.io.NetOutputStream; * *

Данный пакет заставляет сервер переключить текущий {@link State}

* - *

Структура пакета + *

Структура пакета

*
  * | FIELD            | TYPE           | NOTES                                        |
  * |------------------|----------------|----------------------------------------------|
@@ -21,7 +21,7 @@ import mc.protocol.io.NetOutputStream;
  * | Next stage       | VarInt         | ID State на который необходимо переключиться |
  *
  * [1] - Protocol version numbers
- * 

+ * * * @see Handshake * @see State diff --git a/src/main/java/mc/protocol/io/package-info.java b/src/main/java/mc/protocol/io/package-info.java index 388d39a..02e0961 100644 --- a/src/main/java/mc/protocol/io/package-info.java +++ b/src/main/java/mc/protocol/io/package-info.java @@ -7,7 +7,7 @@ Data types | Byte | 1 | Число от -128 до 127 | 8-bit число со знаком | | Unsigned Byte | 1 | Число от 0 до 255 | 8-bit без знаковое число | | Short | 2 | Число от -32768 до 32767 | 16-bit число со знаком | -| Unsigned Short | 2 | Число от -32768 до 32767 | 16-bit без знаковое число | +| Unsigned Short | 2 | Число от 0 до 65535 | 16-bit без знаковое число | | Int | 4 | Число от -2147483648 и 2147483647 | 32-bit число со знаком | | Long | 8 | Число от -9223372036854775808 и 9223372036854775807 | 64-bit число со знаком | | Float | 4 | 32-bit число одинарной точности (IEEE 754-2008) | [1] | diff --git a/src/main/java/mc/protocol/login/client/LoginStartPacket.java b/src/main/java/mc/protocol/login/client/LoginStartPacket.java index f235376..b6f37e1 100644 --- a/src/main/java/mc/protocol/login/client/LoginStartPacket.java +++ b/src/main/java/mc/protocol/login/client/LoginStartPacket.java @@ -11,12 +11,12 @@ import mc.protocol.io.NetOutputStream; * *

Начало авторизации.

* - *

Структура пакета + *

Структура пакета

*
  * | FIELD | TYPE   | NOTES            |
  * |-------|--------|------------------|
  * | Name  | String | Имя/Логин игрока |
- * 

+ * * * @see Login start * @see State diff --git a/src/main/java/mc/protocol/login/server/DisconnectPacket.java b/src/main/java/mc/protocol/login/server/DisconnectPacket.java index bf0d0e0..c4985a8 100644 --- a/src/main/java/mc/protocol/login/server/DisconnectPacket.java +++ b/src/main/java/mc/protocol/login/server/DisconnectPacket.java @@ -14,12 +14,12 @@ import mc.protocol.utils.json.JsonUtils; * *

Отключение клиента сервером с указанием причины.

* - *

Структура пакета + *

Структура пакета

*
  * | FIELD  | TYPE | NOTES                            |
  * |--------|------|----------------------------------|
  * | Reason | Text | Причина отключения. Опционально. |
- * 

+ * * * @see Login start * @see State diff --git a/src/main/java/mc/protocol/status/PingPacket.java b/src/main/java/mc/protocol/status/PingPacket.java index 6b2dacf..f06890c 100644 --- a/src/main/java/mc/protocol/status/PingPacket.java +++ b/src/main/java/mc/protocol/status/PingPacket.java @@ -5,6 +5,20 @@ import mc.protocol.Packet; import mc.protocol.io.NetInputStream; import mc.protocol.io.NetOutputStream; +/** + * Пинг. + * + *

Пакет для обмена "пингом".

+ * + *

Структура пакета

+ *
+ * | FIELD   | TYPE | NOTES       |
+ * |---------|------|-------------|
+ * | Payload | Long | Любое число |
+ * 
+ * + * @see Ping + */ @Data public class PingPacket implements Packet { diff --git a/src/main/java/mc/protocol/status/server/StatusServerResponse.java b/src/main/java/mc/protocol/status/server/StatusServerResponse.java index 9d2c513..ac430f9 100644 --- a/src/main/java/mc/protocol/status/server/StatusServerResponse.java +++ b/src/main/java/mc/protocol/status/server/StatusServerResponse.java @@ -12,14 +12,14 @@ import mc.protocol.utils.json.JsonUtils; * *

Информация о сервере

* - *

Структура пакета + *

Структура пакета

*
  * | FIELD         | TYPE   | NOTES                                   |
  * |---------------|--------|-----------------------------------------|
  * | JSON Response | String | Информация о сервере в JSON формате [1] |
  *
  * [1] - Server List Ping: Response
- * 

+ * */ @Data public class StatusServerResponse implements Packet {