docs: present Shacraft Core and its documentation in English

This commit is contained in:
Emil
2026-09-14 17:58:30 +03:00
parent b6ba064339
commit 26748912c6
18 changed files with 643 additions and 620 deletions
+42 -42
View File
@@ -1,80 +1,80 @@
# Сервер, протокол и эксплуатация MVP
# MVP server, protocol, and operation
## Запуск
## Running the server
Нужны Rust 1.96+ и современный браузер с WebGL2. Java не нужна для запуска Shacraft: проверенный каталог включён в исходники. Node 22+ используется для проверок клиента и сети.
Rust 1.96+ and a modern browser with WebGL2 are required. Java is not needed to run Shacraft: the verified catalog is included in the source tree. Node 22+ is used for client and network checks.
```sh
cargo build --release --locked --workspace
bash scripts/run.sh --data data --listen 127.0.0.1:4000
```
Открыть http://127.0.0.1:4000. Для друзей в локальной сети можно задать `--listen 0.0.0.0:4000`; браузерная проверка SHA-256 требует HTTPS для адресов вне localhost. Для внешней сети нужен обычный HTTPS/WSS reverse proxy. В MVP нет сервиса аккаунтов; имя игрока не является подтверждённой личностью. Контрольный токен выдаётся только владельцу сервера, клиент его не получает.
Open http://127.0.0.1:4000. To let friends connect over a local network, use `--listen 0.0.0.0:4000`; browser SHA-256 verification requires HTTPS for addresses other than localhost. External access requires a standard HTTPS/WSS reverse proxy. The MVP has no account service; a player name is not an authenticated identity. Only the server owner receives the control token; it is never sent to the client.
`--data` — каталог WorldStore, `--cache-sections` — ёмкость общего кэша (по умолчанию 64). `--client` и `--packages` задают каталоги статического клиента и проверенных пакетов. Скрипт запуска явно задаёт пути относительно распакованного проекта. Остановка — Ctrl+C; уже подтверждённые правки не зависят от корректного завершения процесса.
`--data` selects the WorldStore directory; `--cache-sections` sets the shared cache capacity (64 by default). `--client` and `--packages` specify the static client and verified package directories. The startup script explicitly resolves these paths relative to the extracted project. Stop the server with Ctrl+C; already acknowledged edits do not depend on a clean process shutdown.
Первый запуск создаёт лобби, галерею `gallery`, неизменяемую основу Spleef и две независимые арены. Каталог содержит все состояния Java 26.2 и авторский trampoline. Импортированный WorldStore тоже можно открыть сервером; импортированные миры появятся в выборе миров рядом с демонстрационными. Галерея содержит 1 197 образцов состояний по умолчанию на полу 128×128, с шагом 3; это обзор всех типов блоков, а не всех 32 тысяч вариантов. Начальная позиция галереи — `[-50,2,58]`; клиент подгружает её частями по мере перемещения.
The first launch creates a lobby, the `gallery` world, an immutable Spleef base, and two independent arenas. The catalog contains every Java 26.2 block state and an original trampoline. The server can also open an imported WorldStore; imported worlds appear in the world selector alongside the demo worlds. The gallery contains 1,197 default-state samples on a 128×128 floor, spaced 3 blocks apart. It provides an overview of all block types, rather than all 32 thousand state variants. The gallery spawn is `[-50,2,58]`; the client loads the world in parts as the player moves.
## Владение состоянием
## State ownership
Один выделенный поток владеет WorldStore, физикой и игровым состоянием. HTTP и WebSocket ставят ограниченные команды в очередь. Движение считается 20 раз в секунду: скорость 5 блоков/с, гравитация 20 блоков/с², обычный прыжок 7 блоков/с. Игрок занимает AABB 0.6×1.8 блока; позиция задаёт середину стоп. Оси +Y вверх, yaw растёт вправо, pitch вверх; направление взгляда `[sin(yaw)*cos(pitch),sin(pitch),-cos(yaw)*cos(pitch)]`.
One dedicated thread owns WorldStore, physics, and game state. HTTP and WebSocket handlers enqueue bounded commands. Movement runs at 20 ticks per second: speed is 5 blocks/s, gravity is 20 blocks/s², and the normal jump impulse is 7 blocks/s. The player's AABB is 0.6×1.8 blocks; the position specifies the center of their feet. +Y points up, yaw increases to the right, and pitch increases upward; the viewing direction is `[sin(yaw)*cos(pitch),sin(pitch),-cos(yaw)*cos(pitch)]`.
Игровые позиции и точки появления ограничены диапазоном ±32 700 по каждой оси: физика этого клиента использует `f32`. Хранилище и конвертер сохраняют более широкий контракт ±30 000 000; это не обещание игровой физики на дальних координатах. Выход игрока за игровой диапазон возвращает его на spawn, а в активном матче означает выбывание.
Gameplay positions and spawn points are limited to ±32,700 on each axis because this client's physics uses `f32`. Storage and the converter retain their wider ±30,000,000 contract; this does not guarantee gameplay physics at distant coordinates. A player who leaves the gameplay range returns to spawn, or is eliminated during an active match.
Ввод содержит намерение двигаться, а не позицию. Сервер проверяет дальность 6 блоков, ближайшее пересечение форм, ячейку установки, пересечение с игроком и правила арены. Просроченный ввод обнуляется через секунду. Игровая физика использует ограниченную область соседних блоков на каждый тик; независимые миры без игроков не требуют массива загруженных секций.
Input expresses movement intent rather than position. The server checks the 6-block reach, the nearest shape intersection, the placement cell, intersections with players, and arena rules. Stale input is cleared after one second. Gameplay physics reads a bounded region of neighboring blocks for each tick; independent worlds without players need no array of loaded sections.
В `worlds.sqlite3` хранятся блоки и их история. В `server.sqlite3` — конфигурация и сохраняемые сущности с отдельной ревизией. Это две транзакционные области: создание мира и добавление его настроек не заявляются одной общей транзакцией. Если сохранение настроек не удалось после создания мира, мир доступен с безопасными настройками по умолчанию; ошибку нельзя интерпретировать как разрешение повторно создать тот же мир. Для сущностей и настроек неуспешная запись восстанавливает состояние из последней сохранённой версии. Если даже чтение SQLite невозможно, операция возвращает ошибку; ошибка хранения не объявляется успешным подтверждением.
`worlds.sqlite3` stores blocks and their history. `server.sqlite3` stores configuration and persistent entities, with a separate revision. These are two transaction domains: creating a world and adding its settings are not claimed to form one shared transaction. If saving settings fails after world creation, the world remains available with safe defaults; the error must not be interpreted as permission to create the same world again. A failed entity or settings write restores state from the last saved version. If even reading SQLite fails, the operation returns an error; a storage failure is never acknowledged as success.
## HTTP и авторизация
## HTTP and authorization
Публичные GET: `/api/health`, `/api/manifest`, `/api/worlds`, `/api/catalog`, `/api/entities`, `/api/metrics`. Каталог принимает `query`, `offset`, `limit` (1–256) `ids` с максимум 128 runtime ID или `states` с каноническими состояниями, разделёнными запятыми вне скобок свойств. Runtime ID берётся из ответа; он не совпадает с числовым ID Minecraft.
Public GET endpoints: `/api/health`, `/api/manifest`, `/api/worlds`, `/api/catalog`, `/api/entities`, `/api/metrics`. The catalog accepts `query`, `offset`, `limit` (1–256), `ids` with at most 128 runtime IDs, or `states` containing canonical states separated by commas outside property brackets. Obtain runtime IDs from the response; they do not match Minecraft's numeric IDs.
`POST /api/control` принимает `{ "method": "world.read", "params": {...} }`, возвращает `{ "result": ... }` или HTTP 400 с `{ "error": "..." }`. Требуется `Authorization: Bearer <token>`. При первом запуске файл `control.token` создаётся с режимом 0600 на Unix. Параметры операций доступны в схемах `tools/list` отдельного MCP. Названия Control API используют точку: `world.edit`, `build.plan`, `camera.capture` и т.д.
`POST /api/control` accepts `{ "method": "world.read", "params": {...} }` and returns `{ "result": ... }`, or HTTP 400 with `{ "error": "..." }`. It requires `Authorization: Bearer <token>`. On the first launch, `control.token` is created with Unix mode 0600. Operation parameters are available in the separate MCP server's `tools/list` schemas. Control API names use a dot: `world.edit`, `build.plan`, `camera.capture`, and so on.
Токен не является секретом от администратора локальной машины. Хеш manifest подтверждает совместимость ресурсов; он не доказывает неизменность исполняемого кода клиента. Защита игрового состояния основана на серверных проверках. Origin для браузерного WebSocket и Control API проверяется; межсайтовый доступ не включён.
The token is not secret from the local machine's administrator. The manifest hash confirms resource compatibility; it does not prove that the client's executable code is unmodified. Game state protection relies on server-side validation. Browser WebSocket and Control API requests are subject to Origin checks; cross-site access is not enabled.
## WebSocket, снимки и правки
## WebSocket, snapshots, and edits
Первое сообщение на `/ws` в течение 10 секунд:
Send the first message to `/ws` within 10 seconds:
```json
{"type":"join","protocol":1,"manifest_hash":"из /api/manifest","name":"Игрок","world":"lobby"}
{"type":"join","protocol":1,"manifest_hash":"from /api/manifest","name":"Player","world":"lobby"}
```
`welcome` содержит `id`, `world`, `revision`, `blocks:[{pos,block}]`, определения использованных `materials`, `players`, `entities`, `spawn`, `view_center` и `manifest_hash`. Снимок покрывает `[centerX-32, centerY-8, centerZ-32]…[centerX+31, centerY+31, centerZ+31]`, максимумы включительные. При перемещении центра видимости сервер присылает новый `snapshot`; клиент полностью заменяет геометрию. Полный строковый реестр в снимке не передаётся. `materials` ограничен 256 записями и 128 КиБ; остальные определения клиент последовательно запрашивает через `/api/catalog?ids=1,2,...&limit=128`. Это позволяет войти в мир с большой палитрой, не переполняя исходящую очередь.
`welcome` contains `id`, `world`, `revision`, `blocks:[{pos,block}]`, definitions of the `materials` in use, `players`, `entities`, `spawn`, `view_center`, and `manifest_hash`. A snapshot covers `[centerX-32, centerY-8, centerZ-32]…[centerX+31, centerY+31, centerZ+31]`, with inclusive upper bounds. When the view center moves, the server sends a new `snapshot`; the client replaces its geometry completely. Snapshots do not include the full string registry. `materials` is limited to 256 entries and 128 KiB; the client requests the remaining definitions sequentially through `/api/catalog?ids=1,2,...&limit=128`. This allows players to join worlds with large palettes without overflowing the outbound queue.
Клиент отправляет `input` с `seq,yaw,pitch,forward,strafe,jump`; `break` с `pos`; `place` с `pos,block` или `state`; `switch_world`, `resync`, `respawn`, `start_match`, `chat`, `ping`. Ответ `state` содержит авторитетные позиции, `tick`, подтверждённый `ack` и состояние матча. Блоки приходят в `blocks` с новой ревизией. При пропуске ревизии клиент запрашивает снимок. Подписка и создание снимка сериализованы с правками в одном потоке, поэтому промежуточная правка не теряется.
The client sends `input` with `seq,yaw,pitch,forward,strafe,jump`; `break` with `pos`; `place` with `pos,block` or `state`; and `switch_world`, `resync`, `respawn`, `start_match`, `chat`, and `ping`. A `state` response contains authoritative positions, `tick`, the acknowledged input `ack`, and match state. Blocks arrive in `blocks` messages with a new revision. If a revision is missing, the client requests a snapshot. Subscription and snapshot creation are serialized with edits on the same thread, so an edit made between those steps cannot be lost.
Для управляющих правок сохраняется контракт ядра: ожидаемая ревизия, уникальный `operation_id`, durable-подтверждение, повтор того же запроса без второй записи, отказ при конфликте. План строительства занимает не более 32 768 ячеек, хранится 5 минут, максимум 16 планов; preview не меняет мир. Планы эфемерны и исчезают после перезапуска, принятые правки остаются на диске. `camera.capture` возвращает PNG изометрической серверной проекции и точную ревизию; это не кадр WebGL-камеры игрока.
Control edits retain the core contract: an expected revision, a unique `operation_id`, a durable acknowledgment, replay of the same request without a second write, and rejection on conflict. A build plan covers at most 32,768 cells and is retained for 5 minutes, with at most 16 plans stored; preview does not change the world. Plans are ephemeral and disappear after a restart; accepted edits remain on disk. `camera.capture` returns a PNG of the server's isometric projection and the exact revision; it is not a frame from the player's WebGL camera.
## Правила Spleef
## Spleef rules
Матч проходит `waiting → countdown → active → finished → waiting`. По умолчанию нужны 2 игрока, отсчёт занимает 3 секунды, раунд — до 180 секунд. Разрешено разрушать только `minecraft:snow_block` в активном раунде; установка блоков и разрушение границы запрещены. Падение ниже Y=−6 означает выбывание. При одном оставшемся участнике объявляется победитель; истечение времени с несколькими оставшимися даёт ничью. После результата через 5 секунд мир возвращается к своему закреплённому шаблону, игроки — на spawn. Арены независимы. Отключение/уход из мира исключает участника; повторный вход во время раунда остаётся входом зрителя. После перезапуска прерванный матч сбрасывается к шаблону.
A match follows `waiting → countdown → active → finished → waiting`. Defaults are 2 required players, a 3-second countdown, and a round lasting up to 180 seconds. Only `minecraft:snow_block` may be broken during an active round; block placement and boundary destruction are forbidden. Falling below Y=−6 eliminates a player. The last remaining participant wins; if time expires with multiple participants remaining, the result is a draw. Five seconds after the result, the world returns to its pinned template and players return to spawn. Arenas are independent. Disconnecting or leaving the world removes a participant; rejoining during the round admits them as a spectator. After a restart, an interrupted match resets to its template.
`arena.configure` сохраняет настройки мира. Изменять их можно между матчами; попытка во время countdown/active/finished отклоняется. Доступны `mode`, `spawn` и следующие поля:
`arena.configure` persists world settings. They can be changed between matches; attempts during countdown/active/finished are rejected. Available fields are `mode`, `spawn`, and:
- `countdown_seconds`: целое 1…30, по умолчанию 3; `round_seconds`: целое 1…3600, по умолчанию 180.
- `min_players`: целое 2…32, по умолчанию 2.
- `elimination_y`: конечная координата в пределах ±32 700, по умолчанию −6.
- `spawn_points`: до 32 точек `[x,y,z]`. Пустой список означает круг радиуса 7 вокруг X/Z=0 на высоте `spawn[1]`. Непустой список должен вмещать минимум участников, а при старте — всех вошедших; точки располагаются не ближе 0.8 блока друг к другу.
- `spectator_spawn`: точка зрителя, по умолчанию `[13,2,0]`.
- `floor_block`: известное каноническое состояние с коллизией, которое участникам разрешено разрушать. По умолчанию `minecraft:snow_block`. Пол в закреплённой карте должен уже содержать этот материал; configure не перекрашивает и не перестраивает карту.
- `countdown_seconds`: integer 1…30, default 3; `round_seconds`: integer 1…3600, default 180.
- `min_players`: integer 2…32, default 2.
- `elimination_y`: a finite coordinate within ±32,700, default −6.
- `spawn_points`: up to 32 `[x,y,z]` points. An empty list uses a circle of radius 7 around X/Z=0 at height `spawn[1]`. A nonempty list must accommodate the minimum player count and, at match start, every player who has joined; points must be at least 0.8 blocks apart.
- `spectator_spawn`: spectator position, default `[13,2,0]`.
- `floor_block`: a known canonical state with collision that participants are allowed to break. Default: `minecraft:snow_block`. The pinned map's floor must already contain this material; configure does not repaint or rebuild the map.
Все точки появления находятся в игровом диапазоне, их Y выше `elimination_y + 0.5`. Необязательный `expected_revision` проверяет общую ревизию метаданных, доступную через `entity.list`/`metrics`; это отдельная ревизия от блоков мира. Правила возвращаются в `match.rules`. Старые настройки с двумя полями `mode/spawn` читаются с указанными значениями по умолчанию.
All spawn points must be within the gameplay range, with Y above `elimination_y + 0.5`. The optional `expected_revision` checks the shared metadata revision available through `entity.list`/`metrics`; this is separate from world block revisions. Rules are returned in `match.rules`. Older settings containing only `mode/spawn` are read using the defaults above.
Журнал идемпотентности ядра относится к правкам блоков, undo/reset и подтверждению плана. Операции сущностей и настройки арен пока не имеют такого журнала: повторный `entity.spawn` создаёт ещё один экземпляр. После неопределённого сетевого результата сначала следует прочитать текущее состояние.
The core idempotency journal covers block edits, undo/reset, and build commits. Entity operations and arena configuration do not yet have such a journal: repeating `entity.spawn` creates another instance. After an uncertain network result, read the current state first.
## Лимиты и наблюдаемость
## Limits and observability
- 32 WebSocket-сессии, включая ожидающие join; 16 одновременно обслуживаемых HTTP-запросов, очередь 64 команд.
- Входное сообщение WebSocket до 64 КиБ, максимум 80 сообщений/с на соединение; действия блоков не чаще 110 мс, чат не чаще 700 мс, явный resync не чаще 500 мс, переход между мирами не чаще секунды, автоматический снимок при смене секции не чаще 2 секунд.
- Control API до 2 МиБ JSON; штатная правка до 32 768 ячеек; чтение до 262 144 ячеек и 6 МиБ ответа; при превышении байтового лимита требуется уменьшить область.
- Исходящая очередь на клиента: 16 сообщений и 8 МиБ. При переполнении или превышении срока отправки медленное соединение закрывается. Общее верхнее ограничение очередей зависит от числа клиентов; эти байты не следует путать с кэшем секций.
- Метаданные сервера до 8 МиБ, до 4096 сущностей, свойства одной сущности до 16 КиБ. В игровые снимки входят компактные представления без произвольного JSON свойств; полные свойства читаются через `entity.list` с offset и limit (по умолчанию 64, максимум 128).
- RAM процесса в `/api/metrics` — фактический Linux VmRSS, а `storage.cache_payload_bytes` — только полезные байты кодированных секций. Каталог, строки, SQLite, сетевые буферы, временные чтения и память аллокатора существуют отдельно.
- 32 WebSocket sessions, including those waiting to join; 16 concurrently served HTTP requests; a 64-command queue.
- WebSocket input messages up to 64 KiB, with at most 80 messages/s per connection; block actions no more often than every 110 ms, chat every 700 ms, explicit resync every 500 ms, world switches every second, and automatic snapshots on section changes every 2 seconds.
- Control API JSON up to 2 MiB; standard edits up to 32,768 cells; reads up to 262,144 cells and 6 MiB of response data. Exceeding the byte limit requires a smaller region.
- Each client's outbound queue holds up to 16 messages and 8 MiB. A slow connection is closed if its queue overflows or sending times out. The aggregate queue bound depends on the number of clients; these bytes are separate from the section cache.
- Server metadata up to 8 MiB, at most 4096 entities, and up to 16 KiB of properties per entity. Gameplay snapshots contain compact representations without arbitrary property JSON; full properties are available through `entity.list` with offset and limit (default 64, maximum 128).
- Process RAM in `/api/metrics` is the actual Linux VmRSS; `storage.cache_payload_bytes` counts only the payload bytes of encoded sections. The catalog, strings, SQLite, network buffers, temporary reads, and allocator memory are separate allocations.
Максимальная разрешённая конфигурация лимитов не равна измеренному целевому профилю нагрузки. Условия и результаты benchmark публикуются в VERIFICATION; заявлений о выигрыше относительно Paper без сопоставимого прогона нет.
The maximum allowed configuration is not the measured target load profile. Benchmark conditions and results are published in VERIFICATION; no advantage over Paper is claimed without a comparable run.
## Сущности и совместимость
## Entities and compatibility
158 определений сущностей имеют реальные размеры и авторские процедурные модели. Сохраняемые экземпляры создаются, перемещаются и удаляются через MCP. Полноценные ванильные AI, redstone, жидкости, инвентари и игровая логика Minecraft не реализованы. Формы контекстно зависимых блоков явно отмечены в каталоге. Изменённые и неизвестные данные конвертер обрабатывает по правилам `docs/interop.md`, без молчаливого объявления lossless-совместимости.
The 158 entity definitions have measured dimensions and original procedural models. Persistent instances can be created, moved, and deleted through MCP. Full vanilla AI, redstone, fluids, inventories, and Minecraft gameplay logic are not implemented. Context-dependent block shapes are explicitly marked in the catalog. The converter handles modified and unknown data according to `docs/interop.md`, without silently claiming lossless compatibility.