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
+51 -26
View File
@@ -1,60 +1,85 @@
# Shacraft Core
Самостоятельный открытый воксельный движок на Rust и работающий локальный MVP: сервер с несколькими мирами, собственный WebGL2-клиент, Spleef, отдельный MCP, каталог Java 26.2, пакеты расширений и конвертер миров. Приоритет — измеренное потребление **серверной RAM**.
[![MVP checks](https://github.com/emil28092005/shacraft-core/actions/workflows/ci.yml/badge.svg)](https://github.com/emil28092005/shacraft-core/actions/workflows/ci.yml)
## Запустить
An independent, open-source voxel engine written in Rust. The local MVP includes an authoritative multiplayer server, a custom WebGL2 client, Spleef arenas, an MCP server, content packages, and Minecraft world import/export. The main engineering priority is **measured server memory use**.
Требуются Rust 1.96+, C-компилятор для SQLite и браузер с WebGL2. Java и Node для игры не нужны. Первый запуск скачает Cargo-зависимости и соберёт release; следующие используют готовый бинарный файл.
> NOT AN OFFICIAL MINECRAFT PRODUCT. NOT APPROVED BY OR ASSOCIATED WITH MOJANG OR MICROSOFT.
Minecraft is mentioned to identify compatibility targets and data sources. Minecraft names, brands, and assets remain the property of their respective owners. See the [Minecraft Usage Guidelines](https://www.minecraft.net/en-us/usage-guidelines).
## Quick start
You need Rust 1.96+, a C compiler for bundled SQLite, and a browser with WebGL2. Java and Node.js are not required to play. The first run downloads Cargo dependencies and builds the release binaries; subsequent runs use the existing binaries.
```bash
git clone https://github.com/emil28092005/shacraft-core.git
cd shacraft-core
bash scripts/run.sh --data data --listen 127.0.0.1:4000
```
Открыть **http://127.0.0.1:4000**. WASD — движение, пробел — прыжок, мышь — обзор, ЛКМ/ПКМ — убрать/поставить блок, E — библиотека, T — чат, F3 — диагностика. Если браузер не даёт захват мыши, обзор работает перетаскиванием. Мир выбирается слева сверху. Для Spleef два игрока входят в одну арену и запускают матч через меню. Лобби, галерея всех типов блоков и две арены создаются автоматически.
Open **http://127.0.0.1:4000**. The server creates a lobby, a block gallery, and two Spleef arenas automatically. The MVP client currently uses Russian interface text.
Вся работа хранится в `--data`. Для остановки используйте Ctrl+C. Подтверждённые правки сохраняются до ответа сервера; проверены аварийные остановки и восстановление.
- **WASD** to move, **Space** to jump, and the mouse to look around. Drag to look if pointer lock is unavailable.
- **Left/right click** to remove/place a block; **E** for the material library, **T** for chat, and **F3** for diagnostics.
- Select a world in the upper-left corner. To play Spleef, two players join the same arena and start a match from the menu.
## Что входит
World data is stored under `--data`. Stop the server with Ctrl+C. Acknowledged block edits are persisted before the server responds; crash recovery is covered by automated checks.
- `shacraft-core`: компактные секции 16³, общий ограниченный кэш, SQLite/WAL/FULL, неизменяемые снимки, независимые изменения миров, ревизии, идемпотентные правки, undo/reset. Без графики и сети.
- `shacraft-server`: авторитетные движение, формы столкновений и взаимодействия, WebSocket/HTTP, сохраняемые сущности и настройки, законченный цикл Spleef.
- `client/`: собственный рендерер, библиотека материалов, игроки и сущности, чат, переключение миров, переподключение, загрузка и проверка пакетов.
- `shacraft-mcp`: настоящий отдельный stdio MCP с 17 инструментами, ресурсами и prompt; строительство по плану, чтение, отмена, сущности, арены, метрики и PNG результата.
- `shacraft-content`: **1 196 блоков, 32 366 состояний, 158 типов сущностей Java 26.2**, DataVersion 4903. Официальные идентификаторы и измеренные коллизии, авторские модели. Плюс блок trampoline.
- `shacraft-compat`: Anvil и Sponge `.schem` v3 в обе стороны, типизированный NBT, сохранение оригинала, отчёты о преобразованиях и перенос правок сущностей.
- `packages/`: собственные текстуры, звук, шейдер и исполняемый WASM-модуль прыжка с ограничениями памяти и fuel.
## What's included
Ванильные AI, redstone, инвентари и симуляция жидкостей не входят в этот MVP. Контекстные формы отмечены отдельно. Конвертер после правок использует явный `best-effort`; неизменённый оригинал может вернуть побайтно. Это не обещание полной совместимости с механиками Minecraft или модами NeoForge. Оригинальные ресурсы и код Minecraft не распространяются.
- **`shacraft-core`** — compact 16³ sections, a bounded shared cache, SQLite with WAL and FULL synchronization, immutable snapshots, independent world edits, revisions, idempotent operations, undo, and reset. No graphics or networking dependencies.
- **`shacraft-server`** — authoritative movement, collision shapes and interactions, WebSocket/HTTP, persistent entities and settings, and a complete Spleef match cycle.
- **`client/`** — a custom renderer, material library, players and entities, chat, world switching, reconnection, and verified package downloads.
- **`shacraft-mcp`** — a separate stdio MCP server with 17 tools, resources, and a prompt; build plans, reads, undo, entities, arenas, metrics, and PNG previews.
- **`shacraft-content`** — **1,196 blocks, 32,366 states, and 158 entity types from Java 26.2**, DataVersion 4903. Source identifiers, measured collision shapes, and independently authored rendering templates. An additional trampoline block demonstrates extensions.
- **`shacraft-compat`** — Anvil and Sponge `.schem` v3 import/export, typed NBT, preserved originals, conversion reports, and entity edit transfer.
- **`packages/`** — original textures, audio, a shader, and an executable WASM jump module with memory and fuel limits.
## MCP и конвертация
## Compatibility and scope
This MVP does not implement full vanilla AI, redstone, inventories, or fluid simulation. Context-dependent shapes are marked separately. After edits, the converter uses an explicit `best-effort` mode; an unchanged original can be returned byte for byte. Full Minecraft gameplay or NeoForge mod compatibility is not claimed. Minecraft source code, binaries, and original visual/audio assets are not distributed.
The release benchmark measured a maximum of **59.65 MiB RSS/VmHWM with 10 moving clients** and **50.50 MiB RSS with 100 idle world forks**. These are results from a short local workload, not a comparison with Paper or a production capacity guarantee. See [verification and limits](docs/VERIFICATION.md).
## MCP and world conversion
```bash
cargo build --release --locked --workspace
# В конфигурации MCP-клиента запускается этот процесс:
# Configure your MCP client to launch this process:
target/release/shacraft-mcp --server http://127.0.0.1:4000 --data data
# Импорт в новый каталог, затем запуск сервера с --data data/imported:
# Import into a new directory, then run the server with --data data/imported:
target/release/shacraft-compat import-anvil /path/to/java-world data/imported
# Экспорт выполняется при остановленном сервере, в отсутствующий каталог:
# Stop the server before exporting. The destination directory must not exist:
target/release/shacraft-compat export-anvil data/imported artifacts/java-export --mode best-effort
```
Токен Control API создаётся в `data/control.token` (0600 на Unix) и не передаётся браузеру. [MCP](docs/MCP.md), [форматы и команды конвертера](docs/interop.md), [сервер и протокол](docs/SERVER.md), [расширение пакетами](docs/PACKAGES.md).
The Control API token is created at `data/control.token` with mode 0600 on Unix and is never sent to the browser. See [MCP configuration](docs/MCP.md), [converter commands](docs/interop.md), [server protocol](docs/SERVER.md), and [package development](docs/PACKAGES.md).
## Проверить
## Verification
```bash
# Rust, Clippy, аварийное восстановление, JS и реальные HTTP/WebSocket-клиенты:
# Rust checks, crash recovery, JavaScript tests, and real HTTP/WebSocket clients:
bash scripts/verify.sh
# Release-стенд с заранее заданными бюджетами:
# Release benchmark with budgets set before the run:
cargo build --release --workspace --locked
node scripts/benchmark_server.mjs --output artifacts/server-benchmark.json
```
Node 22+ нужен для сетевых/JS-проверок, Python 3 — для проверки аварийного хранения. Настоящий MCP SDK и независимая Java/NBT-проверка описаны в [VERIFICATION](docs/VERIFICATION.md). Проверенные числа и ограничения находятся там; сравнение с Paper не заявляется без сопоставимого стенда.
Node.js 22+ is required for network and JavaScript checks; Python 3 is required for the storage crash test. The independent MCP SDK and Java/NBT verification procedures are documented in [VERIFICATION](docs/VERIFICATION.md). Recorded checks include 84 Rust tests, 6 JavaScript tests, and 14 HTTP/WebSocket scenario groups.
## Контекст
## Documentation
[Требования](docs/REQUIREMENTS.md) · [исходный план](docs/PLAN.md) · [решения](docs/DECISIONS.md) · [контракты ядра](docs/CONTRACT.md) · [состояние и ограничения](docs/STATUS.md) · [контент](docs/CONTENT.md).
- [Project status and limitations](docs/STATUS.md)
- [Requirements](docs/REQUIREMENTS.md), [implementation plan](docs/PLAN.md), and [design decisions](docs/DECISIONS.md)
- [Core contracts](docs/CONTRACT.md), [memory and storage](docs/MEMORY_AND_STORAGE.md), and [development tools](docs/DEVELOPMENT.md)
- [Server](docs/SERVER.md), [client](docs/CLIENT.md), and [MCP](docs/MCP.md)
- [Content catalog](docs/CONTENT.md), [compatibility](docs/COMPATIBILITY.md), [world interchange](docs/interop.md), and [packages](docs/PACKAGES.md)
- [Acceptance criteria](docs/ACCEPTANCE.md) and [verification evidence](docs/VERIFICATION.md)
Проект заново реализован локально после зависания прежней среды. План сохранён до кода отдельным коммитом. Лицензия кода и собственных ресурсов — **MIT или Apache-2.0** на выбор. Существующий лаунчер и продакшен-серверы не изменяются этой поставкой.
## License
The code and original resources are available under **MIT OR Apache-2.0**, at your option. See [LICENSE-MIT](LICENSE-MIT) and [LICENSE-APACHE](LICENSE-APACHE). These licenses do not grant rights to third-party names, brands, or assets.
This project was rebuilt locally after the previous development environment stalled. The plan was committed before implementation. Existing Shacraft launcher and production servers are outside this MVP's integration scope.
+109 -109
View File
@@ -1,149 +1,149 @@
# Приёмка Shacraft Core
# Shacraft Core acceptance criteria
Статус: критерии для локального MVP. Реализованные сценарии и доказательства перечислены в STATUS и VERIFICATION. Этот документ сохраняет исходный план приёмки; ограничения более широких стресс-тестов и совместимости не скрываются общим флагом готовности.
Status: criteria for the local MVP. Implemented scenarios and evidence are listed in STATUS and VERIFICATION. This document preserves the original acceptance plan; limitations in broader stress testing and compatibility are not hidden behind a general readiness flag.
Shacraft Core — самостоятельный открытый движок на Rust. Shacraft-сервер и Spleef проверяют его пригодность на практике. Экономия серверной RAM — основное архитектурное требование. Полный базовый каталог Minecraft 26.2 означает контент, состояния и формы, а не требование воспроизвести архитектуру Minecraft или весь ванильный игровой процесс.
Shacraft Core is an independent open-source Rust engine. The Shacraft server and Spleef test its practical suitability. Reducing server RAM use is the primary architectural requirement. A complete base Minecraft 26.2 catalog means content, states, and shapes; it does not require reproducing Minecraft's architecture or the entire vanilla game.
## Как фиксировать результат
## Recording results
Для каждой проверки сохранять: идентификатор, ревизию исходников, версии инструментов, команду или сценарий, используемые данные, фактический результат и путь к доказательству. Статусы: `не проверено`, `пройдено`, `не пройдено`, `заблокировано` с конкретной причиной. Сборка сама по себе не подтверждает рабочую сетевую игру или корректность импорта.
For every check, retain its identifier, source revision, tool versions, command or scenario, input data, actual result, and path to the evidence. Statuses: `not tested`, `passed`, `failed`, or `blocked`, with a specific reason. A build alone does not establish that networked gameplay works or that imports are correct.
Проверки ниже делятся на два рубежа. Первый позволяет получить работающую основу и быстро обнаруживать ошибки интеграции. Его прохождение не означает завершение полного MVP и не уменьшает исходный объём.
The checks below form two milestones. The first provides a working foundation and helps uncover integration errors quickly. Passing it does not mean that the full MVP is complete or reduce the original scope.
## Рубеж A — минимальный сквозной этап
## Milestone A: minimal end-to-end implementation
### A-CORE: хранение и независимые миры
### A-CORE: storage and independent worlds
- Ядро собирается и используется из отдельного Rust-процесса без HTTP, рендера, браузера и запуска сервера Minecraft.
- Созданы шаблон и два независимых мира на его основе. Изменение блока в первом мире не изменяет шаблон и второй мир. Замена исходного шаблона не меняет уже закреплённую неизменяемую версию.
- Удаление наследуемого блока записывает воздух в наложение, а не возвращает блок шаблона при повторном чтении. Проверить положительные и отрицательные координаты и границы секций.
- `world.edit` принимает пакет изменений целиком или отклоняет его целиком. Устаревшая ревизия, неизвестный блок и недопустимые координаты не оставляют частичных изменений.
- Повтор операции с тем же `operation_id` и тем же содержимым возвращает `replayed: true`, не увеличивает ревизию и не применяет изменение повторно. Повтор идентификатора с другим содержимым должен иметь документированное безопасное поведение; до его определения проверка не закрывается.
- `world.undo` восстанавливает предыдущее содержимое выбранной операции; конфликт с последующими правками обрабатывается по явно описанной политике. Проверить возвращение в наследуемое состояние и удаление наложений.
- `world.reset` восстанавливает выбранную версию шаблона и не повреждает другие миры. Изменение ревизии и судьба журнала операций документированы и проверены.
- `read_region` возвращает правильные ненулевые блоки в включённых границах. Область ровно в 262144 ячейки принимается, превышение лимита и переполнение арифметики границ отклоняются до большой аллокации.
- The core builds and can be used from a separate Rust process without HTTP, rendering, a browser, or a running Minecraft server.
- A template and two independent worlds based on it exist. Changing a block in the first world does not change the template or the second world. Replacing the source template does not change an already pinned immutable version.
- Deleting an inherited block records air in the overlay, rather than returning the template block on the next read. Check positive and negative coordinates and section boundaries.
- `world.edit` accepts or rejects an entire batch of changes atomically. A stale revision, unknown block, or invalid coordinates leave no partial changes.
- Repeating an operation with the same `operation_id` and content returns `replayed: true`, does not increase the revision, and does not apply the edit again. Reusing an identifier with different content must have documented safe behavior; this check cannot be closed until that behavior is defined.
- `world.undo` restores the previous content of the selected operation; conflicts with subsequent edits follow an explicit policy. Check restoration of inherited state and removal of overlays.
- `world.reset` restores the selected template version without damaging other worlds. Its revision change and treatment of the operation journal are documented and tested.
- `read_region` returns the correct nonzero blocks within inclusive bounds. A region of exactly 262144 cells is accepted; exceeding the limit or overflowing boundary arithmetic is rejected before a large allocation.
### A-E2E: два клиента, MCP и перезапуск
### A-E2E: two clients, MCP, and restart
Воспроизводимый сценарий выполняется на одной локальной установке из чистого каталога данных:
Run this reproducible scenario on one local installation with a clean data directory:
1. Запустить сервер на `127.0.0.1:4000`, проверить `/api/health`, открыть два независимых браузерных сеанса и подключить MCP отдельным процессом.
2. Оба клиента входят в один мир. Каждый видит геометрию и другого игрока; движение, поворот, прыжок и столкновения работают в общей системе координат из контракта.
3. Первый клиент ломает и ставит доступный блок. Второй получает изменение без перезагрузки. Повторное подключение получает то же состояние и актуальную ревизию.
4. MCP читает область, находит блок через каталог, выполняет изменение с `expected_revision` и `operation_id`. Оба клиента видят правку. Повтор той же операции идемпотентен; намеренно устаревшая ревизия возвращает понятную ошибку.
5. MCP выполняет undo, и оба клиента видят восстановление. MCP получает снимок камеры; PNG открывается и показывает ожидаемый участок мира, а не пустое изображение.
6. Создать второй мир из шаблона, переключить туда одного клиента и изменить блок. Второй клиент, оставшийся в исходном мире, не получает чужие правки или состояния игроков.
7. Записать проверяемые позиции, значения блоков, имена миров, закреплённые шаблоны, идентификаторы блоков и ревизии. Завершить сервер, запустить с тем же каталогом данных и подключить клиентов и MCP заново. Всё записанное совпадает; подтверждённые durable-операции не потеряны.
8. Повторить восстановление после принудительного завершения процесса в контролируемом тесте. Повреждённый или незавершённый хвост записи не делает ранее подтверждённый мир нечитаемым. Если гарантия подтверждения отличается от гарантии `flush`, это заранее отражено в контракте.
1. Start the server at `127.0.0.1:4000`, check `/api/health`, open two independent browser sessions, and connect MCP as a separate process.
2. Both clients enter the same world. Each sees the geometry and the other player; movement, turning, jumping, and collisions use the shared coordinate system defined in the contract.
3. The first client breaks and places an available block. The second receives the change without reloading. Reconnecting retrieves the same state and current revision.
4. MCP reads a region, finds a block through the catalog, and makes an edit with `expected_revision` and `operation_id`. Both clients see the edit. Repeating the same operation is idempotent; an intentionally stale revision returns a clear error.
5. MCP performs undo, and both clients see the restoration. MCP requests a camera image; the PNG opens and shows the expected part of the world rather than a blank image.
6. Create a second world from the template, switch one client to it, and edit a block. The other client, still in the original world, receives neither the other world's edits nor its player states.
7. Record the positions to verify, block values, world names, pinned templates, block identifiers, and revisions. Stop the server, start it with the same data directory, and reconnect the clients and MCP. All recorded values match; acknowledged durable operations have not been lost.
8. Repeat recovery after forcibly terminating the process in a controlled test. A corrupt or incomplete write tail does not make a previously acknowledged world unreadable. If acknowledgement guarantees differ from `flush` guarantees, the contract states this in advance.
Доказательство: журнал действий и ответов протокола, результаты сверки до/после рестарта, снимок двух клиентов. Скрипт протокола дополняет визуальную проверку браузера, но не заменяет её.
Evidence: a log of actions and protocol responses, comparisons before/after restart, and a screenshot of two clients. A protocol script supplements browser visual verification but does not replace it.
### A-SERVER: сервер определяет состояние игры
### A-SERVER: the server determines game state
- Нельзя войти в произвольный неизвестный мир, передать нечисловые/неограниченные координаты или использовать недопустимый `BlockId` и привести к сбою процесса.
- Клиент передаёт ввод; координаты, скорость, столкновения и результат действий определяет сервер. Поддельный пакет с готовой позицией не телепортирует игрока.
- Сервер проверяет дистанцию взаимодействия и доступность действия по состоянию игры. Игрок не ломает далёкие блоки и не редактирует мир, в котором не находится.
- Частота пакетов и размер сообщений ограничены. Поток некорректных, слишком больших и слишком частых сообщений одного соединения не создаёт неограниченную очередь и не лишает второй клиент возможности играть.
- Контрольный HTTP API отвергает отсутствующий и неверный токен. Токен не попадает в публичный manifest, клиентскую сборку, URL или обычные журналы. Файл токена создаётся с правами `0600`.
- Несовместимые версия протокола и manifest приводят к документированному отказу или обновлению до входа. Совпадение заявленного хеша не трактуется как доказательство доверенности программы клиента.
- После разрыва соединения игрок убирается из соответствующего мира; повторное подключение не создаёт бессрочного дубликата сущности.
- Attempting to join an arbitrary unknown world, submit nonnumeric/unbounded coordinates, or use an invalid `BlockId` cannot crash the process.
- The client sends input; the server determines coordinates, velocity, collisions, and action outcomes. A forged packet containing a final position does not teleport the player.
- The server checks interaction distance and whether the game state permits an action. A player cannot break distant blocks or edit a world they are not in.
- Packet rates and message sizes are bounded. A stream of malformed, oversized, or overly frequent messages from one connection cannot create an unbounded queue or prevent the second client from playing.
- The control HTTP API rejects missing and invalid tokens. The token never appears in the public manifest, client build, URLs, or ordinary logs. The token file is created with permissions `0600`.
- Incompatible protocol versions and manifests result in a documented rejection or update before entry. A matching claimed hash is not treated as proof that the client program is trustworthy.
- After a disconnection, the player is removed from the corresponding world; reconnection does not create an indefinite duplicate entity.
### A-CLIENT: играбельный браузерный клиент
### A-CLIENT: a playable browser client
- Клиент запускается по адресу сервера, получает manifest и каталог, отображает блоки, свободное пространство, формы начального набора и игроков.
- Управление камерой, движение, прыжок, выбор блока, установка/удаление и переключение мира доступны без ручной отправки запросов в консоли разработчика.
- Клиент показывает отказ входа, потерю соединения и ошибки действий понятным сообщением; зависшее состояние не выдаётся за подтверждённое сервером.
- Геометрия обновляется после сетевых правок. Начальная загрузка, повторное соединение и смена мира не оставляют геометрию предыдущего мира.
- The client opens at the server address, obtains the manifest and catalog, and displays blocks, open space, shapes from the initial set, and players.
- Camera controls, movement, jumping, block selection, placement/removal, and world switching are available without manually sending requests from the developer console.
- The client explains rejected entry, lost connections, and action errors with clear messages; a stuck state is not presented as server-confirmed.
- Geometry updates after network edits. Initial loading, reconnection, and world switching do not retain geometry from the previous world.
### A-MCP: настоящий отдельный MCP
### A-MCP: a real, separate MCP implementation
- Отдельный процесс MCP успешно проходит `initialize`, объявляет инструменты и выполняет `tools/call` через клиент MCP. Наличие одного `/api/control` не закрывает этот критерий.
- Доступны операции мира, поиск каталога, чтение, пакетная правка, undo, метрики, запуск арены, снимок камеры и объявленные в контракте операции сущностей.
- Схемы аргументов, результаты и ошибки соответствуют фактическому поведению. Недоступный сервер и неверный токен дают ошибку инструмента без зависания MCP-процесса.
- MCP использует тот же контроль ревизий, границ и допустимости данных, что и прочие административные обращения. Поиск ограничивает размер ответа, а чтение не выгружает целый большой мир в контекст.
- A separate MCP process successfully completes `initialize`, advertises tools, and executes `tools/call` through an MCP client. Providing only `/api/control` does not satisfy this criterion.
- World operations, catalog search, reading, batch editing, undo, metrics, arena startup, camera images, and the entity operations declared in the contract are available.
- Argument schemas, results, and errors match actual behavior. An unavailable server or invalid token produces a tool error without hanging the MCP process.
- MCP uses the same revision, boundary, and data-validity checks as other administrative requests. Search limits response size, and reads do not dump an entire large world into context.
### A-SPLEEF: один полный матч
### A-SPLEEF: one complete match
- В арене на общей карте участвуют два клиента. Есть ожидание/подготовка, начало, активная игра и завершение; сервер сообщает фазу и оставшееся время.
- В активной игре разрешено ломать только допустимый слой арены. Установка блоков и правки вне области ограничены правилами режима.
- Падение ниже настроенной границы исключает игрока на сервере. При одном оставшемся участнике объявляется один победитель; при одновременном выбывании и разрыве соединения результат определён правилами.
- Завершение и повторный запуск восстанавливают карту и участников. Параллельная арена на том же шаблоне сохраняет собственное состояние.
- Нельзя дважды запустить уже активный матч и получить несколько таймеров или повторное начисление результата.
- Two clients take part in an arena on a shared map. There are waiting/preparation, start, active play, and completion phases; the server reports the phase and remaining time.
- During active play, only the permitted arena layer can be broken. Block placement and edits outside the region are restricted by the mode's rules.
- Falling below the configured boundary eliminates the player on the server. One winner is declared when a single participant remains; the rules define the outcome of simultaneous eliminations and disconnects.
- Completion and restart restore the map and participants. A parallel arena based on the same template retains its own state.
- Starting an already active match twice cannot create multiple timers or award the result repeatedly.
### A-MEMORY: ограниченность памяти основы
### A-MEMORY: bounded memory in the foundation
- При чтении числа различных секций, превышающего `cache_sections`, количество резидентных секций в кэше не превышает заданную ёмкость. Проверить также ёмкость 0 или её явно документированный отказ.
- Два и более мира с общей неизменяемой основой не получают по полной копии данных карты в RAM. Метаданные миров и их изменения учитываются отдельно.
- Выгрузка изменённой секции сохраняет её изменения; повторное чтение после вытеснения и после рестарта возвращает одинаковый результат.
- История операций хранится на диске. Длинная последовательность правок не требует держать весь журнал и все снимки состояний в RAM.
- Метрики позволяют увидеть хотя бы число миров, резидентных секций и заданную ёмкость кэша. RSS процесса измеряется снаружи; один счётчик кэша не выдаётся за расход памяти всего сервера.
- Reading more distinct sections than `cache_sections` does not increase the number of resident cached sections beyond the configured capacity. Also test a capacity of 0 or its explicitly documented rejection.
- Two or more worlds with a shared immutable base do not each receive a complete copy of the map data in RAM. World metadata and changes are accounted for separately.
- Unloading a modified section preserves its changes; reading it again after eviction and after restart returns the same result.
- Operation history is stored on disk. A long sequence of edits does not require keeping the entire journal and all state snapshots in RAM.
- Metrics expose at least the world count, resident section count, and configured cache capacity. Process RSS is measured externally; a single cache counter is not presented as the entire server's memory use.
## Рубеж B — полный согласованный MVP
## Milestone B: the complete agreed MVP
Все проверки рубежа A обязательны. Дополнительно должны быть завершены следующие части; начальная демонстрация с несколькими блоками их не заменяет.
All milestone A checks are mandatory. The following parts must also be completed; an initial demonstration with a few blocks does not replace them.
### B-CONTENT: полный базовый каталог Minecraft 26.2
### B-CONTENT: the complete base Minecraft 26.2 catalog
- Зафиксированы точная редакция/сборка 26.2, источник каталога и контрольные суммы входных данных. Полнота проверяется сравнением с этим набором, а не заранее придуманным количеством блоков.
- Автоматическая сверка покрывает каждый базовый блок, допустимые состояния, формы рендера и столкновений, а также каждый базовый тип сущности целевого набора.
- Канонические имена и свойства сохраняются без потери при регистрации, хранении, сетевой передаче и рестарте. Неизвестные состояния не заменяются воздухом молча.
- Каталог сущностей включает данные, необходимые для отображения, размещения, хранения и обмена мирами; поведенческие возможности каждого типа явно отмечены. Заглушка для всех типов не считается полным каталогом с рабочими формами.
- Отдельно проверяются отличающиеся от полного куба формы, ориентации, составные блоки, прозрачность и блоки с дополнительными данными. Клиент и сервер используют совместимые формы и свойства.
- Ресурсы воспроизводимо собираются из объявленных источников. Отсутствующий ресурс приводит к диагностике с конкретным идентификатором, а отчёт содержит полный список пробелов.
- The exact 26.2 edition/build, catalog source, and input checksums are recorded. Completeness is checked against that dataset, not a predetermined block count.
- Automated comparison covers every base block, valid states, render and collision shapes, and every base entity type in the target set.
- Canonical names and properties survive registration, storage, network transmission, and restart without loss. Unknown states are not silently replaced with air.
- The entity catalog includes data needed for rendering, placement, storage, and world interchange; each type's behavioral capabilities are explicitly marked. A stub for every type does not count as a complete catalog with working shapes.
- Non-full-cube shapes, orientations, multipart blocks, transparency, and blocks with additional data are checked separately. Client and server use compatible shapes and properties.
- Resources are built reproducibly from declared sources. A missing resource produces a diagnostic with its specific identifier, and the report includes a complete list of gaps.
### B-PACKAGES: единая система модулей и ресурсов
### B-PACKAGES: a unified system for modules and resources
- Один версионируемый формат пакета описывает модули, текстуры, шейдеры и прочие ресурсы, зависимости, совместимость и стороны исполнения.
- Сервер формирует manifest с точными версиями и хешами; клиент автоматически получает требуемые клиентские части, проверяет целостность и повторно использует локальный кэш.
- Проверены отсутствующий пакет, несовместимая версия, цикл зависимостей, повреждённая загрузка, прерывание/возобновление и изменение набора между подключениями. Частичная установка не активируется как полная.
- Серверные файлы и секреты не попадают в клиентскую выдачу. Пакеты не могут писать за пределы каталога установки через относительные пути или архивные записи.
- Расширение регистрирует новый контент через документированный интерфейс; его можно подключить без правки исходников ядра. Права исполнения, доступные API и ограничения ресурсов модуля определены и проверены.
- Проект запускается независимо от Shacraft Launcher. Интерфейс будущей интеграции документирован. Реальное изменение/проверка существующего лаунчера относится к отдельному интеграционному этапу и не блокирует локальный выпуск движка.
- One versioned package format describes modules, textures, shaders, and other resources, dependencies, compatibility, and execution sides.
- The server generates a manifest with exact versions and hashes; the client automatically obtains the required client-side parts, verifies integrity, and reuses its local cache.
- Checks cover a missing package, incompatible version, dependency cycle, corrupt download, interruption/resumption, and changes to the package set between connections. A partial installation is not activated as a complete one.
- Server files and secrets are excluded from client distribution. Packages cannot write outside the installation directory through relative paths or archive entries.
- An extension registers new content through a documented interface and can be connected without editing core source code. Execution permissions, available APIs, and module resource limits are defined and tested.
- The project runs independently of Shacraft Launcher. The future integration interface is documented. Actual changes to or verification of the existing launcher belong to a separate integration stage and do not block a local engine release.
### B-INTEROP: импорт и экспорт Minecraft ↔ Shacraft
### B-INTEROP: Minecraft ↔ Shacraft import and export
- Команды и форматы импорта/экспорта документированы. Есть небольшие эталонные миры целевой версии: несколько измерений, отрицательные координаты, состояния блоков, сущности, данные блок-сущностей и пользовательские данные.
- Импортированный мир открывается сервером и клиентом; выборочная и полная автоматическая сверка эталонов подтверждает координаты, состояния и поддерживаемые данные.
- Цикл `Minecraft → Shacraft → Minecraft` сохраняет поддерживаемые данные семантически. Сравниваются декодированные значения; побайтовое равенство сжатых файлов не требуется.
- Исходные неизвестные или неподдерживаемые данные сохраняются для обратного экспорта, если их смысл нельзя корректно перенести. Экспорт не уничтожает их незаметно после редактирования других частей мира.
- Изменения, сделанные через клиент и MCP, правильно отражаются в экспортированном мире. Отдельно проверяются удаление блока, новые состояния и сущности.
- Отчёт перечисляет сохранённые, преобразованные, неподдерживаемые и потерянные данные с координатой/идентификатором и причиной. Отсутствие данных не маскируется успешным статусом.
- Повреждённый файл, неполная область, неизвестная версия, слишком большая распакованная запись и отмена операции не портят источник и ранее существующий целевой мир.
- Конвертер обрабатывает мир порциями; потребление RAM не растёт до размера всего мира. Эталон, превышающий бюджет кэша, конвертируется успешно.
- Import/export commands and formats are documented. Small reference worlds for the target version cover multiple dimensions, negative coordinates, block states, entities, block-entity data, and custom data.
- The server and client open an imported world; sampled and complete automated comparisons against the fixtures verify coordinates, states, and supported data.
- The `Minecraft → Shacraft → Minecraft` cycle preserves supported data semantically. Decoded values are compared; compressed files need not be byte-identical.
- Original unknown or unsupported data is preserved for export back to the source format when its meaning cannot be transferred correctly. Export does not silently destroy it after edits to other parts of the world.
- Changes made through the client and MCP appear correctly in the exported world. Block deletion, new states, and entities are checked separately.
- The report lists preserved, transformed, unsupported, and lost data, with a coordinate/identifier and reason. Missing data is not concealed behind a success status.
- A corrupt file, incomplete region, unknown version, oversized decompressed record, or cancelled operation does not damage the source or a pre-existing target world.
- The converter processes the world in portions; RAM use does not grow to the size of the entire world. A reference dataset larger than the cache budget converts successfully.
### B-PERSISTENCE: устойчивое состояние сервера
### B-PERSISTENCE: durable server state
- На диске сохраняются миры, закреплённые версии шаблонов, реестр контента, правки, необходимые данные undo, конфигурация и правила арен, а также сохраняемые сущности.
- Политика восстановления активного матча после рестарта определена: восстановление или безопасный сброс. Результат не оставляет навсегда активную арену и не дублирует победу.
- Проверены прерывания в момент записи секций, метаданных и журнала. Восстановление выбирает целостную версию; данные, на которые уже получено durable-подтверждение, сохраняются согласно контракту.
- Версия формата хранения проверяется при открытии. Несовместимая версия вызывает понятный отказ или проверяемую миграцию с возможностью восстановления исходных данных.
- Worlds, pinned template versions, the content registry, edits, required undo data, arena configuration and rules, and persistent entities are stored on disk.
- The policy for an active match after restart is defined: resume or safely reset. The result leaves neither a permanently active arena nor a duplicated victory.
- Interruptions during section, metadata, and journal writes are tested. Recovery selects a consistent version; data already acknowledged as durable survives according to the contract.
- The storage format version is checked on open. An incompatible version produces a clear refusal or a verifiable migration that allows recovery of the original data.
### B-MEMORY: доказанная экономия серверной RAM
### B-MEMORY: demonstrated server RAM savings
Benchmark запускается на фиксированном наборе данных и оборудовании. До измерения фиксируются лимиты, размер карты, количество миров и игроков, частота правок, объём активных областей и допустимый запас RSS; выбранные значения публикуются вместе с результатом.
Run the benchmark on a fixed dataset and hardware. Before measurement, record limits, map size, world and player counts, edit rate, active region volume, and permitted RSS headroom; publish these values with the results.
- Сравнить 1, 10 и 100 независимых миров одного большого шаблона: без игроков, с одинаковой активной областью и с различными активными областями. Допускается рост метаданных и изменённых данных; полная копия карты на мир отсутствует.
- Для каждого варианта записать RSS/p95/пик, резидентные секции и их байты, размер наложений, число игроков, сетевые очереди, скорость/задержку тика и размер данных на диске.
- После обхода областей размером больше кэша неактивные секции вытесняются. Повторные обходы и циклы создания/сброса миров не вызывают постоянного линейного роста удерживаемой памяти.
- Медленный клиент, длинный журнал, частые снимки MCP и параллельные импорты не обходят лимиты через очереди, буферы ответов и вспомогательные кэши.
- Целевые лимиты памяти и задержки тика соблюдаются на опубликованной нагрузке. Без заранее зафиксированного бюджета можно подтвердить ограниченность отдельных структур, но нельзя объявлять достигнутым конкретный масштаб сервера.
- Compare 1, 10, and 100 independent worlds based on one large template: without players, with the same active region, and with different active regions. Metadata and changed data may grow; there is no complete map copy per world.
- For each variant, record RSS/p95/peak, resident sections and their bytes, overlay size, player count, network queues, tick rate/latency, and on-disk data size.
- After traversing regions larger than the cache, inactive sections are evicted. Repeated traversals and world creation/reset cycles do not cause continuous linear growth in retained memory.
- A slow client, long journal, frequent MCP images, and concurrent imports cannot bypass limits through queues, response buffers, or auxiliary caches.
- Target memory and tick-latency limits hold under the published load. Without a predefined budget, individual structures can be shown to be bounded, but a specific server scale cannot be claimed as achieved.
### B-DELIVERY: воспроизводимый открытый проект
### B-DELIVERY: a reproducible open-source project
- В репозитории есть исходники самостоятельного Rust-ядра, отдельного сервера, клиента, MCP, конвертера, пакетов базового контента и примера режима; границы зависимостей проверяемы сборкой.
- Чистая установка по README воспроизводит сборку, тесты и сценарий A-E2E. Конфигурация, порты, команды запуска, каталог данных и получение токена описаны явно.
- Документированы API расширений, протокол, формат пакетов, хранение, гарантии сохранности и ограничения совместимости; выбранная открытая лицензия присутствует в репозитории.
- Архив выпуска создан, повторно распакован в чистый каталог и проверен. В него не включены токены, локальные миры пользователя и зависимости, которые должны загружаться отдельно.
- Итоговый отчёт ссылается на доказательства для каждого обязательного критерия. Непроверенные или заблокированные требования перечислены явно и не называются завершёнными.
- The repository contains source for the independent Rust core, separate server, client, MCP, converter, base-content packages, and an example game mode; dependency boundaries can be verified by building.
- A clean installation following the README reproduces the build, tests, and A-E2E scenario. Configuration, ports, startup commands, the data directory, and obtaining the token are described explicitly.
- Extension APIs, the protocol, package format, storage, durability guarantees, and compatibility limitations are documented; the chosen open-source license is present in the repository.
- A release archive has been created, extracted again into a clean directory, and verified. It contains no tokens, the user's local worlds, or dependencies that must be downloaded separately.
- The final report links to evidence for every mandatory criterion. Untested or blocked requirements are listed explicitly and are not called complete.
## Что нужно уточнить в CONTRACT.md по ходу реализации
## Items to clarify in CONTRACT.md during implementation
Эти решения можно проработать без остановки первого сквозного этапа. До приёмки соответствующей части полного MVP они должны стать явными контрактами и тестами:
These decisions can be developed without stopping the first end-to-end milestone. Before accepting the corresponding part of the complete MVP, they must become explicit contracts and tests:
- Версия протокола, идентификаторы ошибок, лимиты пакетов/координат/строк, восстановление клиента при пропуске ревизии и семантика `switch_world`.
- Момент durable-подтверждения, replay с различными аргументами, конфликты undo, ревизия после reset, формат и срок хранения истории.
- Источник точной версии каталога 26.2, схема форм и состояний, каталог/сохранение сущностей и дополнительных данных блоков.
- Формат пакета, граф зависимостей, публикация ресурсов сервером, интерфейс и пределы исполнения модулей, интеграция лаунчера.
- Настройки арены, допустимые действия, таймеры, ничья, отключение игрока и политика сохранения матча.
- Форматы и команды импорта/экспорта, сохранение неподдерживаемых данных и машиночитаемый отчёт о потерях.
- Общий бюджет RAM, лимиты помимо кэша секций, целевая нагрузка и параметры воспроизводимого benchmark.
- Protocol version, error identifiers, package/coordinate/string limits, client recovery after a missed revision, and `switch_world` semantics.
- The point of durable acknowledgement, replay with different arguments, undo conflicts, the revision after reset, and history format and retention.
- The exact 26.2 catalog source, shape and state schemas, the entity catalog and persistence, and additional block data.
- Package format, dependency graph, server resource publication, module interfaces and execution limits, and launcher integration.
- Arena settings, permitted actions, timers, draws, player disconnection, and match persistence policy.
- Import/export formats and commands, preservation of unsupported data, and a machine-readable loss report.
- The overall RAM budget, limits beyond the section cache, target load, and reproducible benchmark parameters.
+20 -20
View File
@@ -1,33 +1,33 @@
# Браузерный клиент MVP
# MVP browser client
Клиент находится в `client/` и раздаётся `shacraft-server` по `/`. Сборщик, npm-зависимости и готовый игровой движок не нужны: это ES-модули и собственный WebGL2-рендерер. Откройте `http://127.0.0.1:4000` после запуска сервера. Поддерживаются современные настольные браузеры с WebGL2; `localhost` или HTTPS необходим для `crypto.subtle` и проверки пакетов.
The client lives in `client/` and is served by `shacraft-server` at `/`. It uses ES modules and its own WebGL2 renderer, with no bundler, npm dependencies, or off-the-shelf game engine. Open `http://127.0.0.1:4000` after starting the server. Modern desktop browsers with WebGL2 are supported; `localhost` or HTTPS is required for `crypto.subtle` and package verification.
## Управление
## Controls
- Нажмите на мир, чтобы захватить мышь. Если браузер запрещает захват, удерживайте кнопку и перетаскивайте для обзора.
- WASD или стрелки — движение; пробел — прыжок. Направление определяется камерой, +Y вверх, yaw 0 смотрит вдоль −Z. Позиция игрока задаёт ступни.
- ЛКМ — убрать выбранный блок, ПКМ — поставить блок на выбранной грани, средняя кнопка — взять выбранный материал в текущую ячейку.
- 1–9 или колесо мыши — ячейка панели. E — библиотека всех состояний; поиск использует английские Minecraft-идентификаторы. Выбор заменяет текущую ячейку.
- T или Enter — чат, Enter отправляет, Esc закрывает.
- Кнопка имени мира открывает выбор экземпляра. F3 открывает диагностику. Меню содержит имя игрока, возвращение к точке появления и запуск Spleef.
- Esc освобождает мышь; отпускание фокуса и открытие панели отправляют нулевой ввод, чтобы игрок не продолжал движение.
- Click the world to capture the mouse. If the browser blocks pointer lock, hold the mouse button and drag to look around.
- WASD or arrow keys move; Space jumps. Movement follows the camera; +Y is up, and yaw 0 looks along −Z. The player's position specifies their feet.
- Left-click removes the selected block, right-click places a block against the selected face, and middle-click copies the selected material into the current hotbar slot.
- 1–9 or the mouse wheel selects a hotbar slot. E opens the library of all states; search uses English Minecraft identifiers. Selecting a state replaces the current slot.
- T or Enter opens chat, Enter sends, and Esc closes it.
- The world-name button opens the instance selector. F3 opens diagnostics. The menu contains the player name, return-to-spawn action, and Spleef start action.
- Esc releases the mouse. Losing focus or opening a panel sends zero input so the player does not keep moving.
## Рендер и синхронизация
## Rendering and synchronization
Геометрия строится по локальным box-формам материалов. Сетки разбиты на секции 16³; общие грани полных непрозрачных кубов отбрасываются. Изменение блока пересобирает его секцию и смежные секции. Шейдер использует направленный свет, туман, пиксельную фактуру и авторскую текстуру из проверенного пакета. Небо и солнце также рисуются WebGL. Прозрачные материалы рисуются отдельным проходом с сортировкой секций по расстоянию (внутри секции порядок прозрачных поверхностей упрощён). Пакет с декларативным стилем `effect: bounce` (включая trampoline и пользовательские блоки) подключает текстуру, проверенную GLSL-функцию подсветки и авторский звук; отклик привязан к полученному от сервера подъёму игрока. Формы сущностей берутся из каталога; игроки имеют отдельные составные аватары. Это собственное упрощённое визуальное представление, а не точное воспроизведение Minecraft.
Geometry is built from each material's local box shapes. Meshes are divided into 16³ sections; shared faces between full opaque cubes are culled. A block change rebuilds its section and adjacent sections. The shader uses directional lighting, fog, a pixelated surface pattern, and an original texture from a verified package. The sky and sun are also drawn with WebGL. Transparent materials use a separate pass with sections sorted by distance; transparent surface ordering within each section is simplified. A package with the declarative style `effect: bounce` (including the trampoline and custom blocks) supplies a texture, a verified GLSL highlight function, and an original sound; the response is tied to the player's upward movement received from the server. Entity shapes come from the catalog; players have separate multipart avatars. These are original, simplified visuals rather than an exact reproduction of Minecraft.
Клиент отправляет ввод максимум 20 раз в секунду, не объявляет собственную позицию и не изменяет блоки оптимистически. Сервер рассчитывает движение, столкновения и правки, а клиент сглаживает полученные позиции между кадрами. Это добавляет небольшую задержку движения, зато визуальное положение следует авторитетной симуляции. Камера реагирует на мышь локально.
The client sends input at most 20 times per second, never declares its own position, and does not edit blocks optimistically. The server computes movement, collisions, and edits, while the client smooths received positions between frames. This introduces a small movement delay but keeps the displayed position aligned with the authoritative simulation. The camera responds to the mouse locally.
`welcome` и `snapshot` полностью заменяют видимую геометрию. Полный `registry` необязателен: снимок содержит не больше 256 описаний используемых материалов, остальные формы клиент постепенно запрашивает через `/api/catalog?ids=...&limit=128`. Каждый ответ достраивает только затронутые секции; до получения формы отображается нейтральный куб. События `blocks` применяются только по порядку ревизий; данные за пределами последнего окна 64×40×64 отбрасываются, сохраняя продвижение ревизии. Пропуск запрашивает `resync`; старые ревизии игнорируются. При потере соединения клиент переподключается с задержкой 1, 2, 4, 8, 16, затем 20 секунд. Ошибки подключения, несовместимого протокола, ресурсов и отказанные сервером действия выводятся пользователю.
`welcome` and `snapshot` replace all visible geometry. A full `registry` is optional: snapshots contain at most 256 definitions of materials in use, and the client gradually fetches the remaining shapes through `/api/catalog?ids=...&limit=128`. Each response rebuilds only affected sections; a neutral cube is displayed until its shape arrives. `blocks` events are applied only in revision order; data outside the latest 64×40×64 window is discarded while the revision still advances. A gap triggers `resync`; old revisions are ignored. After a disconnect, the client retries after 1, 2, 4, 8, 16, then 20 seconds. Connection failures, incompatible protocols, resource errors, and actions rejected by the server are shown to the user.
## Пакеты
## Packages
До WebSocket-входа клиент получает `/api/manifest`, загружает объявленные клиентские файлы с того же сервера, проверяет их размер и SHA-256 и сохраняет содержимое в CacheStorage по хешу. Кэшированные файлы повторно проверяются. Отказ кэша не отменяет проверку целостности. При несовпадении хеша файл удаляется из кэша, вход не выполняется. Максимум одного файла — 64 МиБ, набора за загрузку — 128 МиБ, кэш — 512 последних записей. Это ограничения проверяемого содержимого; браузерные сетевые буферы и декодирование изображений также используют память.
Before joining through WebSocket, the client fetches `/api/manifest`, downloads the declared client files from the same server, verifies their sizes and SHA-256 hashes, and stores their contents in CacheStorage keyed by hash. Cached files are verified again. Cache failure does not skip integrity verification. A hash mismatch removes the file from the cache and prevents joining. A single file is limited to 64 MiB, the set verified per download to 128 MiB, and the cache to its 512 most recent entries. These limits apply to verified contents; browser network buffers and image decoding also consume memory.
Токен Control API клиенту не передаётся. В браузере не выполняется произвольный привилегированный JavaScript из пакетов. Проверка клиентом хешей означает совместимость ресурсов и не доказывает неизменность самого клиента на устройстве игрока.
The Control API token is never sent to the client. Packages do not execute arbitrary privileged JavaScript in the browser. Client-side hash verification establishes resource compatibility; it does not prove that the client itself is unmodified on the player's device.
## Отладка и проверки
## Debugging and checks
F3 показывает настоящие значения: мир, ревизию, число видимых блоков и сущностей, игроков, WebGL, FPS, треугольники, тик, подтверждённый ввод, координаты, пакеты и доступные серверные метрики. На `#world-canvas` есть `data-world`, `data-revision`, `data-blocks`, `data-entities`, `data-webgl`, `data-connected`; они обновляются раз в секунду для автоматизированной браузерной проверки. Секреты и управляющие команды через DOM не выставляются.
F3 displays real values: world, revision, visible block and entity counts, players, WebGL, FPS, triangles, tick, acknowledged input, coordinates, packages, and available server metrics. `#world-canvas` exposes `data-world`, `data-revision`, `data-blocks`, `data-entities`, `data-webgl`, and `data-connected`; these update once per second for automated browser checks. Secrets and control commands are not exposed through the DOM.
Проверки чистой математики: `cd client && npm test`. Проверяются оси камеры и проекция, отрицательные координаты, ближайшая грань, ограничения дальности и точное попадание в неполные формы. Визуальная и сквозная проверка выполняется с настоящим сервером отдельно от этих unit-тестов.
Run the pure math checks with `cd client && npm test`. They cover camera axes and projection, negative coordinates, the nearest face, reach limits, and exact hits on non-full-block shapes. Visual and end-to-end checks use a real server separately from these unit tests.
+17 -17
View File
@@ -1,30 +1,30 @@
# Совместимость с Minecraft Java 26.2
# Minecraft Java 26.2 compatibility
Проверено 14 сентября 2026 года. Реализованы полный каталог целевой версии и двусторонний конвертер с явно определённым профилем точности. Подробные контракты и команды: [CONTENT](CONTENT.md), [interop](interop.md), [SERVER](SERVER.md).
Verified on September 14, 2026. A complete catalog for the target version and a bidirectional converter are implemented, with an explicitly defined fidelity profile. Detailed contracts and commands: [CONTENT](CONTENT.md), [interop](interop.md), [SERVER](SERVER.md).
## Источник
## Source
Mojang выпустила [Java 26.2](https://www.minecraft.net/en-us/article/minecraft-java-edition-26-2) 16 июня 2026 года. [Официальный launcher manifest](https://piston-meta.mojang.com/mc/game/version_manifest_v2.json) указал точные [метаданные версии](https://piston-meta.mojang.com/v1/packages/bc42e43dfe43d65a2f6c2c1dbb322c75134e51fe/26.2.json):
Mojang released [Java 26.2](https://www.minecraft.net/en-us/article/minecraft-java-edition-26-2) on June 16, 2026. The [official launcher manifest](https://piston-meta.mojang.com/mc/game/version_manifest_v2.json) identified the exact [version metadata](https://piston-meta.mojang.com/v1/packages/bc42e43dfe43d65a2f6c2c1dbb322c75134e51fe/26.2.json):
- Server JAR: `823e2250d24b3ddac457a60c92a6a941943fcd6a`, 60 894 273 байта; Java major 25.
- DataVersion, извлечённый из целевой версии: **4903**.
- Отчёты и публичный API подтвердили **1 196 блоков**, **32 366 состояний**, **158 сущностей**.
- Все состояния сопоставляются по канонической строке и множеству свойств, не только по общему количеству.
- Server JAR: `823e2250d24b3ddac457a60c92a6a941943fcd6a`, 60,894,273 bytes; Java major version 25.
- DataVersion extracted from the target version: **4903**.
- Reports and the public API confirmed **1,196 blocks**, **32,366 states**, and **158 entities**.
- Every state is compared by canonical string and property set, not just by total count.
`scripts/catalog_generate.py` проверяет артефакт, извлекает отчёты и измеряет коллизии. Повторное извлечение дало побайтно одинаковые сжатые каталоги. JAR остаётся в игнорируемом кэше; исходный код, текстуры, модели и звуки Minecraft в дистрибутив не включаются.
`scripts/catalog_generate.py` verifies the artifact, extracts reports, and measures collisions. Repeating the extraction produced byte-identical compressed catalogs. The JAR remains in an ignored cache; Minecraft source code, textures, models, and sounds are not included in the distribution.
## Что означает поддержка
## Scope of support
`identity`, `render`, `collision` и `behavior` — отдельные поля. Все ванильные состояния известны; 179 контекстных состояний явно помечены `approximate-context`. Остальные коллизии измерены при воздушных соседях и пустом контексте сущности. Это не обещает контекстную эквивалентность во всех ситуациях. Визуальные модели авторские процедурные, а не ванильные. Невидимые служебные блоки намеренно не получают видимую геометрию.
`identity`, `render`, `collision`, and `behavior` are separate fields. All vanilla states are known; 179 context-dependent states are explicitly marked `approximate-context`. Other collisions were measured with air neighbors and an empty entity context. This does not promise contextual equivalence in every situation. Visual models use original procedural geometry rather than vanilla assets. Invisible technical blocks intentionally receive no visible geometry.
158 типов сущностей имеют измеренные размеры, сохраняемые экземпляры и собственные формы. Полноценная AI, redstone, инвентари, генератор и симуляция жидкостей не реализованы. Неизвестные импортированные состояния сохраняются в реестре и видимы как отмеченная заглушка; они не подменяются воздухом в данных.
The 158 entity types have measured dimensions, persistent instances, and original geometry. Full AI, redstone, inventories, terrain generation, and fluid simulation are not implemented. Unknown imported states remain in the registry and appear as a marked placeholder; the stored data does not replace them with air.
Числовой runtime BlockId Shacraft не равен Minecraft state ID. Конвертер сопоставляет канонические строки; одинаковые названия в независимых WorldStore могут иметь разные внутренние номера.
Shacraft's numeric runtime BlockId is not a Minecraft state ID. The converter matches canonical strings; identical names in independent WorldStore instances can have different internal numbers.
## Проверенный обмен
## Verified interchange
Anvil импортируется по одному chunk с типизированным NBT, включая измерения и непрозрачные дополнительные данные. Неизменённый `exact` возвращает сохранённый оригинал после проверки хешей. После правок `exact` консервативно отказывает. `best-effort` переносит изменения блоков и поддержанных свойств сущностей, инвалидирует зависимые данные и сохраняет неподдержанные данные с отчётом и исходником.
Anvil imports one chunk at a time using typed NBT, including dimensions and opaque extra data. An unchanged `exact` export returns the preserved original after checking its hashes. After edits, `exact` conservatively refuses to export. `best-effort` transfers block changes and supported entity properties, invalidates dependent data, and preserves unsupported data with a report and the original source.
Sponge `.schem` v3 поддерживается в обе стороны. Обмен между разными форматами не обещает преобразования всей семантики биомов/block entities: неперенесённые данные архивируются и отмечаются в отчёте. Старые версии, legacy `.schematic`, structure `.nbt` и полная миграция произвольных DataVersion не объявляются поддержанными.
Sponge `.schem` v3 is supported in both directions. Conversion between formats does not promise to translate all biome/block entity semantics: data that is not transferred is archived and identified in the report. Older versions, legacy `.schematic`, structure `.nbt`, and complete migration of arbitrary DataVersion values are not claimed as supported.
Новый, неизменённый и отредактированный экспорт прочитаны официальными Java 26.2 `NbtIo`, `RegionFile`, `SerializableChunkData`, `PrimaryLevelData`, `WorldGenSettings` и читателем сущностей. Независимый nbtlib проверил Sponge и типы NBT. Это проверка официальных codecs без запуска игрового сервера и принятия EULA; игровой плейтест в Minecraft не заявляется.
New, unchanged, and edited exports were read by the official Java 26.2 `NbtIo`, `RegionFile`, `SerializableChunkData`, `PrimaryLevelData`, `WorldGenSettings`, and entity reader. Independent nbtlib checks verified Sponge and NBT types. These checks used official codecs without launching the Minecraft game/server or accepting its server startup prompt; no in-game Minecraft playtest is claimed.
+35 -35
View File
@@ -1,14 +1,14 @@
# Каталог, формы и единые пакеты MVP
# MVP catalog, geometry, and unified packages
Встроенный каталог фактически извлечён из **Minecraft Java 26.2**, `DataVersion = 4903`: **1 196 блоков, 32 366 состояний, 158 типов сущностей**. Проверка сравнивает полные множества состояний, числовые ID источника, состояния по умолчанию, свойства и типы сущностей с отдельной проекцией официальных отчётов. Дополнительно зарегистрирован собственный `shacraft:trampoline`: всего 1 197 блоков и 32 367 состояний.
The built-in catalog was extracted from **Minecraft Java 26.2**, `DataVersion = 4903`: **1,196 blocks, 32,366 states, and 158 entity types**. Validation compares the complete sets of states, source numeric IDs, default states, properties, and entity types against a separate projection of the official reports. The project's own `shacraft:trampoline` is also registered, bringing the total to 1,197 blocks and 32,367 states.
Числовой `minecraft_id` — только идентификатор источника. Сервер отдельно регистрирует канонические строки в `WorldStore`; внутренний `BlockId` зависит от истории конкретного хранилища. Нельзя использовать `minecraft_id` в операциях редактирования мира. Для собственного состояния значение `minecraft_id = u32::MAX` означает отсутствие ID Minecraft.
The numeric `minecraft_id` identifies a state in the source only. The server registers canonical strings separately in `WorldStore`; its internal `BlockId` depends on the history of that particular store. Do not use `minecraft_id` in world editing operations. For a custom state, `minecraft_id = u32::MAX` means that no Minecraft ID exists.
## Происхождение и воспроизведение
## Provenance and reproduction
Источник: [официальный server.jar Java 26.2](https://piston-data.mojang.com/v1/objects/823e2250d24b3ddac457a60c92a6a941943fcd6a/server.jar). SHA-1 `823e2250d24b3ddac457a60c92a6a941943fcd6a`, размер 60 894 273 байта. Полные SHA-256, версия Java, команды и контрольные суммы отчётов находятся в `crates/shacraft-content/data/provenance.json`.
Source: [official Java 26.2 server.jar](https://piston-data.mojang.com/v1/objects/823e2250d24b3ddac457a60c92a6a941943fcd6a/server.jar). SHA-1: `823e2250d24b3ddac457a60c92a6a941943fcd6a`; size: 60,894,273 bytes. Full SHA-256 hashes, the Java version, commands, and report checksums are recorded in `crates/shacraft-content/data/provenance.json`.
Генератор проверяет закреплённые размер и SHA-1 перед использованием JAR:
The generator checks the pinned size and SHA-1 before using the JAR:
```sh
python3 scripts/catalog_generate.py --java /path/to/java25/bin/java
@@ -17,55 +17,55 @@ cargo test -p shacraft-content
cargo run -p shacraft-content --example catalog_report
```
Нужен установленный JDK 25 или новее, включая `javac`. Проверенный локальный runtime: Microsoft OpenJDK 25.0.1+8-LTS. Скрипт не меняет системную Java. `--reuse-reports` позволяет повторно упаковать уже полученные локальные отчёты; полное воспроизведение выполняют без него. Gzip имеет фиксированный `mtime=0`; содержимое каталога детерминировано. В provenance меняется время запуска.
An installed JDK 25 or later, including `javac`, is required. The verified local runtime is Microsoft OpenJDK 25.0.1+8-LTS. The script does not change the system Java installation. `--reuse-reports` repackages previously generated local reports; omit it for a full reproduction. Gzip uses a fixed `mtime=0`, and the catalog content is deterministic. The run timestamp changes in the provenance record.
Фактически проверена точка входа:
The following entry point was verified:
```sh
java -Xmx1G -DbundlerMainClass=net.minecraft.data.Main -jar server.jar --reports --output generated
```
`catalog_extract.java` — собственная небольшая программа, вызывающая публичные API реестров и коллизий 26.2. Она не содержит декомпилированного кода. Генератор данных и измерения не запускают игровой сервер, не создают `eula=true`, не принимают соглашений. JAR, распакованные библиотеки, отчёты и Java-классы остаются в игнорируемом `artifacts/catalog-cache`; в дистрибутив входят только минимальные фактические данные совместимости и авторский код.
`catalog_extract.java` is a small original program that calls the public registry and collision APIs in 26.2. It contains no decompiled code. The data generation and measurements run without launching the Minecraft game/server, creating an `eula=true` file, or accepting its server startup prompt. The JAR, extracted libraries, reports, and Java classes remain in the ignored `artifacts/catalog-cache` directory; the distribution contains only minimal factual compatibility data and original code.
## Что проверено у форм
## Geometry verification
Для **каждого из 32 366 состояний** получен `getCollisionShape` официального исполняемого API. Измерение не использует текстуры или визуальные модели. Все измерения завершились без ошибок; после дедупликации осталось 326 различных наборов прямоугольных объёмов.
`getCollisionShape` was obtained from the official executable API for **each of the 32,366 states**. Measurement uses no textures or visual models. All measurements completed without errors, yielding 326 distinct sets of axis-aligned boxes after deduplication.
Базовый контекст измерения — `BlockPos.ZERO`, соседи `air`, отсутствие сущности (`CollisionContext.empty()`). Дополнительно сравнены каменные соседи и `CollisionContext.positionContext(+10/-10)`: различия обнаружены у 32 состояний scaffolding. Помимо них явно помечены классы с зависимостью от сущности/блочной сущности/динамического состояния: powder snow, shulker box, moving piston и big dripleaf. Поэтому покрытие коллизий разделено:
The baseline measurement context uses `BlockPos.ZERO`, neighboring `air`, and no entity (`CollisionContext.empty()`). Additional comparisons used stone neighbors and `CollisionContext.positionContext(+10/-10)`; these revealed differences in 32 scaffolding states. Classes that depend on entities, block entities, or dynamic state are also explicitly marked: powder snow, shulker box, moving piston, and big dripleaf. Collision coverage is therefore divided into:
- 32 187 состояний: `measured-empty-context` — измерена форма в описанном контексте.
- 179 состояний: `approximate-context` — геометрия базового контекста доступна, полной эквивалентности динамических условий нет.
- 1 собственное состояние: `authored-exact`.
- 32,187 states: `measured-empty-context` — geometry measured in the context described above.
- 179 states: `approximate-context` — baseline geometry is available, but dynamic conditions are not fully equivalent.
- 1 custom state: `authored-exact`.
Первое значение **не утверждает эквивалентность во всех произвольных контекстах**. Положение игрока, специальные экипировки, поршневые блочные сущности, открывание shulker box, обновление связей соседей, AI, редстоун и течения жидкостей не следуют из каталога. Сервер реализует собственную симуляцию и явно ограниченные модули.
The first label **does not claim equivalence in every arbitrary context**. Player position, special equipment, piston block entities, opening shulker boxes, updates to connections with neighbors, AI, redstone, and fluid flow cannot be inferred from the catalog. The server provides its own simulation and modules with explicit boundaries.
Отдельные регрессионные проверки подтверждают верхнюю/нижнюю плиту, объём и направления лестниц, открывание двери, пустую коллизию воды, коллизию забора высотой 1.5, контекстную пометку scaffolding/powder snow, валидность границ всех форм. Геометрия коллизий может выходить за клетку: нельзя безусловно ограничивать Y диапазоном `[0,1]`.
Separate regression checks cover top/bottom slabs, stair volumes and orientations, door opening, empty water collision, the 1.5-block fence collision height, context labels for scaffolding/powder snow, and valid bounds for every shape. Collision geometry can extend outside a block cell; Y must not be unconditionally clamped to `[0,1]`.
## Авторское отображение
## Original rendering
`render` и `collision` — разные наборы `Aabb { min, max }`, координаты относительно блока. Рендерер использует собственные процедурные формы и палитру Shacraft. Встроенные PNG, звуковой WAV и GLSL написаны/сгенерированы в этом репозитории; оригинальных ресурсов Minecraft нет.
`render` and `collision` are separate sets of `Aabb { min, max }`, with coordinates relative to the block. The renderer uses Shacraft's own procedural geometry and palette. The bundled PNG files, WAV audio, and GLSL were authored or generated in this repository; no original Minecraft assets are included.
Семейства плит, лестниц, дверей, люков, панелей, сундуков и многих сложных твёрдых блоков используют измеренные объёмы как основу самостоятельной геометрии. Для заборов, стен, открытых калиток, знаков, рельсов, жидкостей, растений, кнопок, рычагов, ковров и других нетвёрдых форм предусмотрены отдельные параметрические шаблоны. Забор рисуется до Y=1, при этом коллизия достигает Y=1.5. У наклонного рельса ступенчатая геометрия; изогнутый рельс — угловая аппроксимация из прямоугольников. Это читаемый авторский стиль, а не копия визуальной точности Minecraft.
Slabs, stairs, doors, trapdoors, panes, chests, and many complex solid block families use measured volumes as a basis for original geometry. Fences, walls, open fence gates, signs, rails, liquids, plants, buttons, levers, carpets, and other non-solid forms have separate parametric templates. A fence is drawn up to Y=1 while its collision reaches Y=1.5. Ascending rails have stepped geometry; curved rails use an angular approximation made of rectangles. This is a readable original style, not a visually exact reproduction of Minecraft.
Покрытие: 32 317 состояний `authored-procedural` и 50 `intentionally-invisible` (включая воздух, технический light/barrier/structure void и moving piston без исходной динамической блочной сущности). Универсальных визуальных кубов-заглушек для неизвестных семейств встроенного каталога сейчас нет. При этом каждая декоративная деталь, текст надписей, анимация, waterlogged-жидкость внутри модели и световая симуляция не воспроизводятся автоматически по факту наличия состояния.
Coverage: 32,317 `authored-procedural` states and 50 `intentionally-invisible` states, including air, technical light/barrier/structure void blocks, and moving pistons without their original dynamic block entities. No built-in catalog families currently fall back to a generic visual cube. The existence of a state does not automatically reproduce every decorative detail, sign text, animation, waterlogged fluid inside a model, or lighting simulation.
Для 158 типов сущностей извлечены начальные width/height/eye height, fixed dimensions, категория, summonable/serializable/fire immune, tracking/update interval и все доступные базовые числовые attributes. Эти свойства находятся в `EntityDefinition.properties`. Модели относительно ног — авторские семейства biped, quadruped, aquatic, winged, boat, cart, dragon, arthropod и другие. Служебные marker/interaction/area effect cloud/lightning bolt намеренно невидимы. Display-сущности имеют явно указанную зависимость от свойств экземпляра. Размеры возраста/позы/масштаба и произвольный NBT сохраняются слоем экземпляров; каталог хранит размеры по умолчанию. Наличие модели не означает наличие ванильного AI.
For 158 entity types, the extracted data includes initial width/height/eye height, fixed dimensions, category, summonable/serializable/fire immune flags, tracking/update interval, and all available base numeric attributes. These properties are stored in `EntityDefinition.properties`. Models are positioned relative to the feet and use original biped, quadruped, aquatic, winged, boat, cart, dragon, arthropod, and other families. Technical marker/interaction/area effect cloud/lightning bolt entities are intentionally invisible. Display entities explicitly declare their dependence on instance properties. Age/pose/scale dimensions and arbitrary NBT are preserved by the instance layer; the catalog stores default dimensions. Having a model does not imply vanilla AI support.
## Rust API
- `Catalog::load_builtin() -> Result<Catalog>`: полный встроенный каталог и trampoline.
- `Catalog::load_builtin() -> Result<Catalog>`: the complete built-in catalog and trampoline.
- `catalog.state(canonical_or_block_name)`, `catalog.entity(name)`, `catalog.default_state(name)`.
- `catalog.palette()`: 12 удобных канонических состояний для тестового клиента.
- `catalog.sampler()`: 1 197 образцов по умолчанию в сетке 32 столбца с шагом 3; отдельные клетки относительно пола Y=0, X/Z в пределах ±64. Создание пола и запись в мир — ответственность сервера.
- `catalog.summary()`: количества, раздельное покрытие, версия и ограничения.
- `canonical_state(name, properties)`: сортировка ключей и ограниченная валидация без потери неизвестных свойств.
- Все публичные определения реализуют `Clone`, `Serialize`, `Deserialize`. После десериализации целого `Catalog` следует вызвать `rebuild_indexes()` перед поиском.
- `catalog.palette()`: 12 convenient canonical states for the test client.
- `catalog.sampler()`: 1,197 default samples in a 32-column grid with spacing 3; individual cells are positioned relative to a floor at Y=0, with X/Z within ±64. The server is responsible for creating the floor and writing blocks to the world.
- `catalog.summary()`: counts, separate coverage categories, version, and limitations.
- `canonical_state(name, properties)`: key sorting and limited validation without losing unknown properties.
- All public definitions implement `Clone`, `Serialize`, and `Deserialize`. After deserializing a complete `Catalog`, call `rebuild_indexes()` before performing lookups.
Хранение бинарного встроенного каталога занимает около 246 KiB gzip; при загрузке он распаковывается и создаёт строки/геометрию и индексы. Размер файла не равен RAM каталога. Полные строки 32 тысяч состояний и реестр `WorldStore` нужно учитывать отдельно в RSS измерениях процесса.
The built-in binary catalog occupies about 246 KiB as gzip. Loading decompresses it and creates strings, geometry, and indexes. File size is not the catalog's RAM usage. The complete strings for 32 thousand states and the `WorldStore` registry must be accounted for separately in process RSS measurements.
## Единый формат пакета v1
## Unified package format v1
Каждый подкаталог `packages/` содержит `manifest.json`:
Each subdirectory of `packages/` contains a `manifest.json`:
```json
{
@@ -82,10 +82,10 @@ java -Xmx1G -DbundlerMainClass=net.minecraft.data.Main -jar server.jar --reports
}
```
Пример иллюстрирует схему; действительные размеры и хеши берутся из сгенерированных манифестов. Версии зависимостей точные. `load_packages(root)` проверяет весь граф до выдачи ресурсов: схему, уникальность, зависимости, совпадение версий, циклы, допустимые capabilities, пути, размеры и SHA-256 всех объявленных ресурсов. Один ресурс ограничен 16 MiB, весь пакет — 64 MiB; symlink и traversal в ресурсных путях отвергаются. `read_resource` повторно проверяет хеш и размер при чтении.
This example illustrates the schema; actual sizes and hashes come from the generated manifests. Dependency versions are exact. `load_packages(root)` validates the entire graph before exposing resources: schema, uniqueness, dependencies, matching versions, cycles, allowed capabilities, paths, sizes, and SHA-256 hashes of all declared resources. A resource is limited to 16 MiB and an entire package to 64 MiB; symlinks and traversal in resource paths are rejected. `read_resource` checks the hash and size again when reading.
Scopes: `common` — общие определения; `client` — ресурсы клиента; `server` — внутренние данные и код сервера. `PackageManifest::client_manifest()` исключает серверные ресурсы и capabilities. `Package::public_resource(path)` отказывает для server scope; HTTP-маршрут обязан использовать именно этот метод. Статический сервер не должен раздавать весь каталог `packages/` напрямую.
Scopes: `common` contains shared definitions; `client` contains client assets; `server` contains internal server data and code. `PackageManifest::client_manifest()` excludes server resources and capabilities. `Package::public_resource(path)` denies access to server-scope resources; the HTTP route must use this method. The static server must not serve the entire `packages/` directory directly.
`shacraft.base` включает описание каталога, собственный 64×64 текстурный шум и клиентский стиль. `shacraft.trampoline` включает общее определение блока, 32×32 текстуру сетки, клиентский визуальный эффект, короткий авторский звук, необязательную функцию GLSL и **исполняемый серверный WebAssembly-модуль**. Его экспорт `on_jump() -> f32` возвращает скорость 10 блоков/с; импортов, памяти и внешних системных вызовов нет. WAT-исходник находится рядом. Сервер исполняет бинарный модуль в ограниченной среде; контракт предусматривает лимит топлива 10 000, памяти 1 страницу, проверку диапазона результата. Клиент использует встроенный эффект `bounce` по данным пакета, не произвольный JavaScript из сети. Произвольная среда клиентского кода и полноценная модовая экосистема не объявляются реализованными.
`shacraft.base` includes the catalog description, an original 64×64 noise texture, and client styling. `shacraft.trampoline` includes a shared block definition, a 32×32 grid texture, a client visual effect, a short original sound, an optional GLSL function, and an **executable server WebAssembly module**. Its `on_jump() -> f32` export returns a velocity of 10 blocks/s; the module has no imports, memory, or external system calls. The WAT source is included alongside it. The server executes the binary module in a restricted environment; the contract specifies a fuel limit of 10,000, a memory limit of 1 page, and range validation of the result. The client uses the built-in `bounce` effect according to package data, rather than arbitrary JavaScript from the network. An arbitrary client code runtime and a complete mod ecosystem are not claimed as implemented.
`python3 scripts/catalog_assets.py` детерминированно пересоздаёт все авторские ресурсы и хеши. Ресурсы пакетов доступны на условиях `MIT OR Apache-2.0`, как собственный код проекта. Генерация ничего не скачивает.
`python3 scripts/catalog_assets.py` deterministically regenerates all original assets and hashes. Package assets are available under `MIT OR Apache-2.0`, like the project's original code. Generation downloads nothing.
+4 -4
View File
@@ -46,10 +46,10 @@ Control methods: world.list, world.create {name,template?}, world.reset {world,e
Default server host 127.0.0.1 port 4000, token file data/control.token (0600). No publishing or production access.
## Интегрированные компоненты MVP
## Integrated MVP components
Игровой протокол и границы Control API описаны в SERVER.md, настоящий stdio MCP — в MCP.md, пакеты и WASM — в PACKAGES.md, полный каталог — в CONTENT.md, Anvil/Sponge и типизированные sidecar — в interop.md. Данные документы дополняют контракт ядра выше, не изменяя его durable-правил.
The gameplay protocol and Control API boundaries are documented in SERVER.md; the stdio MCP implementation in MCP.md; packages and WASM in PACKAGES.md; the full catalog in CONTENT.md; and Anvil/Sponge and typed sidecars in interop.md. These documents extend the core contract above without changing its durability rules.
`WorldStore::section_positions(world, after: Option<Pos>, limit)` постранично возвращает эффективные координаты секций 16³, включая унаследованные секции и воздушные overrides, в порядке x/y/z. Лимит 1–4096. Экспорт удерживает единственного писателя и не меняет мир между страницами.
`WorldStore::section_positions(world, after: Option<Pos>, limit)` returns paginated effective coordinates of 16³ sections, including inherited sections and air overrides, ordered by x/y/z. The limit is 1–4096. Export holds the single-writer lock and does not change the world between pages.
История ядра находится на диске. Метаданные сущностей/правил имеют отдельную транзакционную область и ревизию. Планы preview живут 5 минут и не переживают рестарт; принятая правка живёт по контракту WorldStore. Неуспешный metadata commit не публикует изменённое состояние. При прерывании активного матча арена сбрасывается к закреплённой основе на следующем запуске.
Core history is stored on disk. Entity/rule metadata has a separate transaction domain and revision. Preview plans live for 5 minutes and do not survive a restart; an accepted edit follows the WorldStore durability contract. A failed metadata commit does not publish changed state. If an active match is interrupted, its arena resets to the pinned base on the next startup.
+19 -19
View File
@@ -1,37 +1,37 @@
# Решения и границы
# Decisions and boundaries
## D001. Независимый Rust workspace
## D001. Independent Rust workspace
Ядро — библиотека. Сервер, MCP и конвертер — отдельные исполняемые компоненты. Общий реестр, координаты и операции доступны через публичный API. Графика и внешние сервисы не загружаются сервером.
The core is a library. The server, MCP, and converter are separate executable components. The shared registry, coordinates, and operations are available through a public API. The server does not load graphics or external services.
## D002. Сначала хранение и сквозная проверка
## D002. Storage and end-to-end verification first
Начинаем с архитектуры памяти и долговечности; подключаем клиент до завершения полного каталога. Наличие небольшого работающего этапа не меняет конечных требований. Невыполненные пункты остаются в плане.
Start with memory architecture and durability; connect the client before completing the full catalog. A small working milestone does not change the final requirements. Unfinished items remain in the plan.
## D003. Первый тестовый клиент — браузерный
## D003. The first test client runs in the browser
Первый проверочный клиент использует собственный WebGL2-рендерер без готового игрового движка. Это ускоряет проверку двух подключений и MCP на локальной машине. Ядро и сервер остаются Rust. Нативный Rust-клиент не считается реализованным таким клиентом; для самостоятельного нативного выпуска и интеграции с Launcher потребуется отдельный шаг. Клиент не должен навязывать формат хранения серверу.
The first verification client uses a custom WebGL2 renderer without an existing game engine. This makes it quicker to test two connections and MCP on a local machine. The core and server remain in Rust. This client does not count as an implemented native Rust client; a standalone native release and Launcher integration require a separate step. The client must not dictate the server's storage format.
## D004. Серверу нельзя доверять заявлениям клиента о собственной целостности
## D004. The server cannot trust the client's claims about its own integrity
Манифесты/хеши проверяют совместимость и загруженные файлы. Сервер подтверждает игровые действия и передаёт только необходимые данные. Полный запрет модифицированных клиентов на контролируемом игроком устройстве не гарантируется протоколом самопроверки. Подписывание дистрибутива и интеграция лаунчера являются отдельными задачами.
Manifests and hashes verify compatibility and downloaded files. The server validates game actions and sends only the necessary data. A self-check protocol cannot guarantee a complete ban on modified clients running on devices controlled by players. Distribution signing and launcher integration are separate tasks.
## D005. Совместимость с Minecraft — адаптер
## D005. Minecraft compatibility is an adapter
Свой формат мира не является копией Anvil. Версия конвертера и профиля экспорта явная. Неподдерживаемые данные нельзя молча заменять воздухом. Каталог имён не эквивалентен реализации формы, коллизии, поведения и round-trip сохранения.
The native world format is not a copy of Anvil. Converter and export profile versions are explicit. Unsupported data must not be silently replaced with air. A catalog of names is not equivalent to implementing shapes, collisions, behavior, and round-trip preservation.
## D006. Безопасные локальные значения по умолчанию
## D006. Safe local defaults
Сервер слушает localhost. Управляющий API требует отдельный токен; обычный игровой клиент его не получает. Все очереди и объёмы запросов имеют предел. Собственные тестовые каталоги отделены от реальных миров.
The server listens on localhost. The control API requires a separate token that the ordinary game client never receives. All queues and request sizes have limits. Test data directories are separate from real worlds.
## D007. Версии и контракты пока рабочие
## D007. Versions and contracts are provisional
`CONTRACT.md` — начальная спецификация для параллельной разработки, не обещание стабильного публичного API. Изменения согласуются до зависимой реализации и отражаются в документации. Особенно важно проверить атомарность правок, фиксацию шаблонов, ограничения registry и сетевой синхронизации.
`CONTRACT.md` is an initial specification for parallel development, not a promise of a stable public API. Changes are agreed before dependent implementation and reflected in the documentation. Edit atomicity, pinned templates, registry limits, and network synchronization limits require particular attention.
## D008. Надёжное хранение на SQLite/WAL
## D008. Durable storage with SQLite/WAL
Для первой реализации выбираем SQLite с транзакциями, WAL и `synchronous=FULL`, ограниченным кэшем страниц и блокировкой второго писателя. Секции остаются собственными компактными бинарными данными; SQLite хранит ссылки, метаданные и историю. Это позволяет проверять игровой формат без одновременного изобретения механизма надёжных транзакций. Размер файла, объём WAL и собственная память SQLite учитываются отдельно.
The first implementation uses SQLite with transactions, WAL, `synchronous=FULL`, a bounded page cache, and a lock that prevents a second writer. Sections remain custom compact binary data; SQLite stores references, metadata, and history. This lets us verify the game format without also inventing a reliable transaction mechanism. File size, WAL size, and SQLite's own memory are accounted for separately.
## D009. Консервативная отмена в первом этапе
## D009. Conservative undo in the first milestone
Undo разрешён только для последней ревизии, созданной целевой правкой. Любая последующая операция, включая возврат блока к прежнему значению, запрещает такой undo. Это строже будущей избирательной отмены, зато не допускает потери последующих изменений. Ограничение явно указывается в API; сброс арены также является границей истории.
Undo is allowed only at the latest revision created by the target edit. Any subsequent operation, including returning a block to its previous value, prevents that undo. This is stricter than future selective undo, but prevents the loss of later changes. The API states this limitation explicitly; resetting an arena is also a history boundary.
+16 -17
View File
@@ -1,43 +1,42 @@
# Разработка и воспроизведение первого этапа
# Development and storage tools
Это инструменты проверки хранилища. Здесь ещё нет игрового сервера, графического клиента или MCP. Локальный JSON-lines интерфейс CLI не является MCP.
This guide documents the storage tools introduced in the first implementation stage. The current workspace also includes a game server, graphical client, and MCP server; see [README](../README.md) and [STATUS](STATUS.md). The local JSON-lines CLI described below is a storage development interface, not MCP.
## Сборка и проверки
## Build and checks
Нужны Rust/Cargo 1.96.0, C-компилятор для bundled SQLite, Python 3 для проверки аварийного завершения. После загрузки зависимостей `Cargo.lock` фиксирует их версии.
Requirements: Rust/Cargo 1.96.0, a C compiler for bundled SQLite, Python 3 for crash testing, and Node.js 22+ for JavaScript and network checks. `Cargo.lock` pins dependency versions. Run these commands from the repository root:
```bash
cd /home/emil/Desktop/shacraft-core
bash scripts/verify.sh
```
Проверка запускает форматирование, Clippy, Rust-тесты, сборку CLI и отдельные процессы. `check_storage.py` создаёт только временные миры и принудительно завершает только собственный дочерний процесс.
The script checks formatting, runs Clippy and Rust tests, builds the workspace, and runs storage crash checks, JavaScript tests, and HTTP/WebSocket scenarios. `check_storage.py` creates temporary worlds and forcibly terminates only its own child process.
## Демонстрация хранения
## Storage demonstration
```bash
cargo run -p shacraft-tools -- --data data/demo demo
cargo run -p shacraft-tools -- --data data/demo stats
```
`demo` требует пустое хранилище. Создаёт карту пола и два независимых экземпляра, изменяет один, проверяет изоляцию, выполняет undo и reset. Повторный запуск в непустой каталог отклоняется. Для нового прогона укажите другое имя каталога.
`demo` requires an empty store. It creates a floor map and two independent instances, edits one, checks isolation, and exercises undo and reset. Running it again in a nonempty directory is rejected. Use a new directory name for another run.
## Измерение
## Measurement
```bash
cargo build --release -p shacraft-tools
target/release/shacraft-tools --data data/bench-001 --cache 8 benchmark --sections 256 --worlds 100
```
`benchmark` также требует пустое хранилище. Он создаёт 256 различных секций, 100 экземпляров, проходит по данным сверх вместимости кэша и изменяет/сбрасывает каждый экземпляр. В JSON выводятся отдельные измерения RSS/пика всего процесса (на Linux), метрики хранения, длительности и размеры файлов. Данные теста синтетические; игроков, сетевого тика и фоновой симуляции нет. Эти числа не доказывают выигрыш относительно Paper.
`benchmark` also requires an empty store. It creates 256 distinct sections and 100 instances, traverses more data than the cache can hold, and edits/resets each instance. Its JSON output separates whole-process RSS/peak measurements on Linux, storage metrics, durations, and file sizes. This is synthetic test data: no players, network ticks, or background simulation. These numbers do not establish an advantage over Paper.
## JSON-lines сессия
## JSON-lines session
```bash
target/debug/shacraft-tools --data data/manual --cache 8 session
```
По одной JSON-команде на строку:
Send one JSON command per line:
```json
{"op":"register","state":"shacraft:stone"}
@@ -48,7 +47,7 @@ target/debug/shacraft-tools --data data/manual --cache 8 session
{"op":"stats"}
```
Сначала получите реальный ID блока и текущую ревизию, затем передайте их в `edit`:
First obtain the actual block ID and current revision, then pass them to `edit`:
```json
{"op":"edit","world":"world","expected_revision":0,"operation_id":"first-stone","changes":[{"pos":[-1,0,0],"block":1}]}
@@ -56,10 +55,10 @@ target/debug/shacraft-tools --data data/manual --cache 8 session
{"op":"reset","world":"world","expected_revision":2,"operation_id":"reset-world"}
```
ID 1 в этом примере допустим только если ответ регистрации действительно вернул 1. Ответ каждой команды имеет `ok` и `result` либо `error`. Успешный ответ записи выдаётся после возврата долговечного API. Максимальная входная строка — 8 MiB; ограничения на число блоков и объём области действуют дополнительно.
ID 1 is valid in this example only if registration actually returned 1. Each response contains `ok` and either `result` or `error`. A successful write response is sent after the durable API returns. The maximum input line is 8 MiB; block-count and region-volume limits also apply.
## Продолжение разработки
## Further development
Прочитайте STATUS и PLAN. Новые компоненты добавляйте в workspace только вместе с реализацией и командами проверки. Не создавайте пустые исполняемые файлы, которые лишь выводят «готово». Публичный протокол пока проектируется в CONTRACT; окончание первого этапа хранения не закрывает последующие этапы.
Read [STATUS](STATUS.md) and [PLAN](PLAN.md). Add workspace components together with their implementation and verification commands. Do not add empty executables that merely print a success message. Current API boundaries are documented in [CONTRACT](CONTRACT.md) and the component-specific documents; completing the storage stage alone does not establish completion of subsequent stages.
Для живого SQLite-хранилища нельзя считать копию одного `worlds.sqlite3` полной резервной копией: актуальные данные могут быть в WAL. Перед ручным копированием остановите владеющий процесс либо используйте будущий согласованный backup API. Исходный архив проекта намеренно не содержит рабочие миры.
Copying only `worlds.sqlite3` from a live SQLite store is not a complete backup: current data may still be in the WAL. Stop the owning process before manually copying it, or use a future coordinated backup API. Source archives intentionally exclude runtime worlds.
+30 -30
View File
@@ -1,14 +1,14 @@
# Shacraft MCP
`shacraft-mcp` — отдельный процесс с настоящим MCP поверх stdio и JSON-RPC 2.0. Он обращается к авторизованному Control API работающего сервера и не открывает файлы миров напрямую. Сервер хранит и проверяет ревизии, лимиты и долговечность операций.
`shacraft-mcp` is a separate process implementing MCP over stdio and JSON-RPC 2.0. It calls the running server's authorized Control API rather than opening world files directly. The server stores and validates revisions, limits, and operation durability.
```sh
cargo run -p shacraft-mcp -- --server http://127.0.0.1:4000 --data data
```
По умолчанию токен читается из `data/control.token`. Параметр `--token-file /absolute/path/control.token` переопределяет путь. Токен читается при управляющем вызове, поэтому MCP можно запустить раньше сервера. В стандартный вывод пишутся только JSON-RPC-сообщения, одна строка на сообщение; диагностика и CLI-ошибки идут в stderr. Не запускайте через командную обёртку, которая печатает посторонний текст в stdout.
By default, the token is read from `data/control.token`. The `--token-file /absolute/path/control.token` argument overrides this path. The token is read when a control call is made, so MCP can start before the server. Standard output contains only JSON-RPC messages, one per line; diagnostics and CLI errors go to stderr. Do not launch it through a shell wrapper that prints unrelated text to stdout.
Пример записи в конфигурации MCP-клиента (пути заменяются своими абсолютными):
Example MCP client configuration (replace the paths with your own absolute paths):
```json
{
@@ -21,57 +21,57 @@ cargo run -p shacraft-mcp -- --server http://127.0.0.1:4000 --data data
}
```
## Протокол
## Protocol
Поддерживаются версии `2025-11-25`, `2025-06-18`, `2025-03-26`, `2024-11-05`. Сервер возвращает запрошенную поддерживаемую версию или новейшую поддерживаемую. Клиент начинает с `initialize`, затем посылает `notifications/initialized`. До этого доступны только `initialize` и `ping`. Уведомления не вызывают ответов; неизвестные методы запросов получают JSON-RPC-ошибку. Ошибки аргументов и выполнения известных инструментов возвращаются в `result.content` с `isError: true`.
Supported versions are `2025-11-25`, `2025-06-18`, `2025-03-26`, and `2024-11-05`. The server returns the requested version if supported, or its newest supported version otherwise. The client starts with `initialize`, followed by `notifications/initialized`. Before that, only `initialize` and `ping` are available. Notifications receive no response; unknown request methods receive a JSON-RPC error. Argument and execution errors for known tools are returned in `result.content` with `isError: true`.
Реализованы `tools/list`, `tools/call`, `resources/list`, `resources/read`, `resources/templates/list`, `prompts/list`, `prompts/get` и `ping`. Списки небольшие и возвращаются целиком. Подписки, асинхронные задачи и уведомления о смене списков не объявляются. Выполнение последовательное; уведомление об отмене не прерывает уже выполняющийся HTTP-запрос. Сетевой тайм-аут ограничен 20 секундами (установление соединения — 3 секунды).
Implemented methods are `tools/list`, `tools/call`, `resources/list`, `resources/read`, `resources/templates/list`, `prompts/list`, `prompts/get`, and `ping`. Lists are small and returned in full. Subscriptions, asynchronous tasks, and list-change notifications are not advertised. Execution is sequential; a cancellation notification does not interrupt an HTTP request already in progress. The network timeout is 20 seconds, with a 3-second connection timeout.
Строка запроса и HTTP-ответ ограничены 8 МиБ. Слишком длинная входная строка отбрасывается до перевода строки, после чего поток продолжает разбираться. HTTP-редиректы отключены: bearer-токен не передаётся перенаправленному адресу.
Request lines and HTTP responses are limited to 8 MiB. An oversized input line is discarded through its terminating newline, after which stream parsing resumes. HTTP redirects are disabled so the bearer token is not forwarded to a redirected address.
## Инструменты и рабочий процесс
## Tools and workflow
- `world_list`, `world_create`, `world_read`: осмотр миров и создание пустого мира или экземпляра закреплённого шаблона.
- `catalog_search`: точные состояния, runtime ID, формы и сведения о покрытии реализации.
- `world_edit`, `world_undo`, `world_reset`: атомарные правки, консервативная отмена последней операции и возврат к базе.
- `build_plan`, `build_commit`: предварительный расчёт ограниченной постройки из box/line/cylinder и последующая фиксация плана.
- `entity_list`, `entity_spawn`, `entity_update`, `entity_delete`: сохранённые сущности мира и их свойства.
- `arena_configure`, `arena_start`: сохраняемые правила Spleef (время, минимум игроков, высота выбывания, точки появления, материал пола) и запуск матча. Правила нельзя менять во время начавшегося раунда; материал пола задаёт разрешённые для разрушения блоки, но не перестраивает карту.
- `metrics`: измеренный RSS и отдельные оценки полезных данных кэша.
- `camera_capture`: изометрическое изображение мира в формате MCP image plus metadata. Это диагностическая проекция сервера, не снимок WebGL-камеры игрока.
- `world_list`, `world_create`, `world_read`: inspect worlds and create an empty world or an instance of a pinned template.
- `catalog_search`: exact states, runtime IDs, shapes, and implementation coverage information.
- `world_edit`, `world_undo`, `world_reset`: atomic edits, conservative undo of the latest operation, and reset to the base.
- `build_plan`, `build_commit`: preview a bounded structure made of box/line/cylinder primitives, then commit the plan.
- `entity_list`, `entity_spawn`, `entity_update`, `entity_delete`: persistent world entities and their properties.
- `arena_configure`, `arena_start`: persistent Spleef rules (timing, minimum players, elimination height, spawn points, floor material) and match start. Rules cannot change while a round is in progress; the floor material determines which blocks may be broken but does not rebuild the map.
- `metrics`: measured RSS and separate cache payload estimates.
- `camera_capture`: an isometric world image returned as an MCP image plus metadata. This is a server diagnostic projection, not a frame from the player's WebGL camera.
Полные JSON Schema доступны через `tools/list`. Имена инструментов соответствуют Control API с заменой первого `_` на точку, например `world_edit` → `world.edit`.
Complete JSON Schemas are available through `tools/list`. Tool names correspond to Control API names with the first `_` replaced by a dot, for example `world_edit` → `world.edit`.
Для строительства сначала прочитайте ревизию и площадку через `world_list`/`world_read`, найдите точные материалы через `catalog_search`, сформируйте `build_plan`, оцените границы и объём, затем выполните `build_commit` с уникальным `operation_id` в пределах авторизованного запроса. После фиксации проверьте `camera_capture`. При конфликте перечитайте мир и сформируйте новый план. Тот же ключ операции используйте только при повторе идентичного запроса.
To build, first read the revision and site through `world_list`/`world_read`, find exact materials through `catalog_search`, create a `build_plan`, inspect its bounds and volume, then call `build_commit` with a unique `operation_id` within the user's authorized scope. After committing, verify the result with `camera_capture`. On conflict, reread the world and create a new plan. Reuse an operation key only to retry an identical request.
Отмена требует текущую ревизию и `target_operation` исходной правки. Последующие изменения и reset могут сделать отмену недоступной; инструмент не должен перезаписывать их молча.
Undo requires the current revision and the original edit's `target_operation`. Later changes and reset may make undo unavailable; the tool must not silently overwrite them.
## Ресурсы и prompt
## Resources and prompt
Ресурсы `shacraft://server/status`, `shacraft://catalog/blocks`, `shacraft://catalog/entities`, `shacraft://packages` читают публичные сведения сервера. Ресурс блоков даёт начальную ограниченную страницу; полный каталог доступен поиском и пагинацией инструмента.
The resources `shacraft://server/status`, `shacraft://catalog/blocks`, `shacraft://catalog/entities`, and `shacraft://packages` read public server information. The block resource provides an initial bounded page; use tool search and pagination to access the full catalog.
Prompt `construct` принимает строки `world` и `request` и описывает последовательность осмотра, планирования, правки и визуальной проверки. Он не расширяет пользовательское разрешение на действие.
The `construct` prompt accepts `world` and `request` strings and describes the inspection, planning, editing, and visual verification sequence. It does not expand the user's authorization.
Проверки: `cargo test -p shacraft-mcp`. Unit-тесты проверяют переходы жизненного цикла, согласование версии, отсутствие ответов на уведомления, ошибки аргументов и токена, недопустимые JSON-RPC ID, восстановление после слишком большой строки и схемы строительных операций. Сквозные тесты с настоящим сервером выполняются дополнительно.
Run checks with `cargo test -p shacraft-mcp`. Unit tests cover lifecycle transitions, version negotiation, notifications receiving no responses, argument and token errors, invalid JSON-RPC IDs, recovery after an oversized line, and build-operation schemas. Additional end-to-end tests use a real server.
Основание протокола: официальные [lifecycle](https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle), [stdio transport](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports) и [tools](https://modelcontextprotocol.io/specification/2025-11-25/server/tools).
Protocol references: the official [lifecycle](https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle), [stdio transport](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports), and [tools](https://modelcontextprotocol.io/specification/2025-11-25/server/tools) specifications.
## Проверка настоящим MCP SDK
## Verification with the real MCP SDK
После запуска отдельного тестового сервера:
After starting a separate test server:
```sh
node crates/shacraft-mcp/tests/sdk-smoke.mjs --data /absolute/path/test-server-data
```
Скрипт использует `@modelcontextprotocol/sdk` (проверен с 1.30.0), выполняет согласование протокола, читает все ресурсы, вызывает prompt, делает правку/повтор/конфликт/отмену, план/фиксацию, получает PNG, проверяет CRUD сущностей и reset. Он создаёт отдельный мир с префиксом `mcp_sdk_`. Путь к установленному SDK задаётся через `SHACRAFT_MCP_SDK`; в локальной среде поддерживается соседний `minecraft-builder-mcp/bridge/node_modules`. Это независимая проверка протокола, не зависимость исполняемого MCP от Minecraft Builder.
The script uses `@modelcontextprotocol/sdk` (verified with 1.30.0), negotiates the protocol, reads every resource, invokes the prompt, exercises edit/replay/conflict/undo and plan/commit, receives a PNG, and checks entity CRUD and reset. It creates a separate world prefixed with `mcp_sdk_`. Set `SHACRAFT_MCP_SDK` to the installed SDK path; the local environment also supports a sibling `minecraft-builder-mcp/bridge/node_modules` directory. This independently verifies the protocol; the MCP executable does not depend on Minecraft Builder.
Для воспроизводимой проверки с автоматически запущенным отдельным сервером:
For a reproducible check with an automatically started separate server:
```sh
node scripts/check_mcp.mjs --binary target/release/shacraft-server --mcp-binary target/release/shacraft-mcp --port 4002 --output artifacts/mcp-sdk.json
```
Обёртка создаёт временный каталог данных, использует настоящий SDK и закрывает тестовый сервер. Рабочий сервер на порту 4000 не затрагивается. `--sdk` или `SHACRAFT_MCP_SDK` задают путь к уже установленному SDK; результат записывается JSON-файлом, включая ошибку при неуспешной проверке.
The wrapper creates a temporary data directory, uses the real SDK, and stops the test server. It does not affect the working server on port 4000. `--sdk` or `SHACRAFT_MCP_SDK` specifies the path to an already installed SDK; results are written to a JSON file, including the error if verification fails.
Связанный сквозной тест `scripts/check_server.mjs` проверяет HTTP/WebSocket-клиенты, действия, экземпляры миров, полный матч и восстановление после реального `SIGKILL`: подтверждённые блоки, сущности и правила арены должны пережить перезапуск того же каталога данных. Временные тестовые данные сохраняются для разбора.
The related end-to-end test, `scripts/check_server.mjs`, checks HTTP/WebSocket clients, actions, world instances, a complete match, and recovery after a real `SIGKILL`: acknowledged blocks, entities, and arena rules must survive restarting with the same data directory. Temporary test data is retained for investigation.
+111 -111
View File
@@ -1,188 +1,188 @@
# Память, хранение и восстановление Shacraft Core
# Shacraft Core memory, storage, and recovery
Статус: план новой реализации с принятыми решениями D008–D009. Этот файл задаёт инварианты и критерии проверки; он не утверждает, что перечисленные механизмы уже реализованы. Публичный API находится в [CONTRACT.md](CONTRACT.md), принятые решения — в [DECISIONS.md](DECISIONS.md). Дополнительные предложения отдельно перечислены в конце.
Status: implementation plan incorporating decisions D008–D009. This file defines invariants and verification criteria; it does not claim that all mechanisms listed here have already been implemented. The public API is in [CONTRACT.md](CONTRACT.md), and accepted decisions are in [DECISIONS.md](DECISIONS.md). Additional proposals are listed separately at the end.
## 1. Главная цель и граница обещаний
## 1. Primary goal and scope of guarantees
Главная цель ядра — ограничить серверную RAM при большом числе независимых матчей на одинаковых картах. Неизменённые блоки общего шаблона хранятся один раз. Матч владеет только собственными изменениями. Данные неактивных областей и история операций остаются на диске.
The core's primary goal is to bound server RAM when many independent matches use identical maps. Unchanged blocks in a shared template are stored once. A match owns only its changes. Inactive areas and operation history remain on disk.
Нельзя заранее обещать процент экономии относительно Paper или конкретное число игроков на гигабайт. Экономия зависит от разнообразия блоков, числа одновременно активных секций, степени изменения карт, сущностей, клиентской видимости и нагрузки. Успех подтверждают воспроизводимые измерения вместе с функциональными ограничениями реализации.
Do not promise a percentage saving relative to Paper or a specific number of players per gigabyte in advance. Savings depend on block diversity, the number of simultaneously active sections, how much maps change, entities, client visibility, and workload. Success is demonstrated by reproducible measurements alongside the implementation's functional limitations.
Бюджет процесса включает больше, чем блоки: кэш секций, временные декодированные секции, индекс хранилища, реестр блоков, метаданные миров, историю, очереди сети, игроков и сущности. Ограничение одного кэша не означает ограничения всей RAM.
The process budget includes more than blocks: the section cache, temporary decoded sections, storage indexes, block registry, world metadata, history, network queues, players, and entities. Bounding one cache does not bound all RAM.
## 2. Адресация и формат секции
## 2. Addressing and section format
Единица хранения — секция 16 × 16 × 16, то есть 4096 ячеек. Координаты мира остаются знаковыми `i32` из контракта. Для каждой оси использовать `div_euclid(16)` и `rem_euclid(16)`: блок `-1` попадает в секцию `-1`, локальную координату `15`. Индекс ячейки: `x + 16*z + 256*y`. Этот порядок фиксируется версией формата.
The storage unit is a 16 × 16 × 16 section, or 4,096 cells. World coordinates remain signed `i32` values as specified by the contract. Use `div_euclid(16)` and `rem_euclid(16)` on each axis: block `-1` belongs to section `-1` at local coordinate `15`. The cell index is `x + 16*z + 256*y`. The format version fixes this order.
В первом этапе секция выбирает компактную uniform/palette кодировку:
In the first stage, a section chooses a compact uniform/palette encoding:
- `Uniform(BlockId)`: все 4096 блоков одинаковы; массив индексов отсутствует.
- `Paletted`: уникальные глобальные `BlockId` и плотно упакованные индексы палитры. Для `P > 1` требуется `ceil(log2(P))` бит на ячейку.
- `Uniform(BlockId)`: all 4,096 blocks are identical; there is no index array.
- `Paletted`: unique global `BlockId` values and densely packed palette indices. For `P > 1`, each cell requires `ceil(log2(P))` bits.
Будущее расширение `Dense` может хранить 4096 глобальных `u32`, если палитра вместе с индексами занимает больше места. Это требует явной версии/тега кодировки и пока не входит в принятый минимальный контракт.
A future `Dense` extension may store 4,096 global `u32` values when the palette and its indices take more space. This requires an explicit encoding version/tag and is not yet part of the accepted minimum contract.
Без заголовков и выравнивания палитра занимает `4*P + 4096*ceil(log2(P))/8` байт. При двух состояниях это 520 байт, при 16 — 2112, при 256 — 5120. При 4096 уникальных состояниях получается 22528 байт, поэтому прямой массив в 16384 байта выгоднее. Это расчёт полезных данных, а не RSS и не размер объекта Rust.
Without headers or alignment, a palette occupies `4*P + 4096*ceil(log2(P))/8` bytes. That is 520 bytes for two states, 2,112 for 16, and 5,120 for 256. With 4,096 unique states it reaches 22,528 bytes, making a direct 16,384-byte array smaller. This calculates payload size, not RSS or Rust object size.
При чтении одного блока не нужно распаковывать всю секцию. Изменение использует временный массив на 4096 значений и затем заново выбирает кодировку. Палитра после редактирования должна удалять неиспользуемые состояния. Дисковое сжатие можно добавить после замеров; оно не заменяет ограничение кэшей.
Reading one block should not require decoding the entire section. An edit uses a temporary array of 4,096 values, then selects the encoding again. Editing must remove unused states from the palette. Disk compression can be added after measurement; it does not replace cache limits.
Декодер проверяет версию, длины, размер палитры, диапазон каждого индекса и существование глобальных `BlockId`. Повреждённая секция возвращает ошибку с её идентификатором; подмена повреждения воздухом запрещена. Кодировка имеет фиксированный порядок байтов и контроль целостности. Контрольная сумма обнаруживает повреждение, но не является защитой от намеренной подмены.
The decoder validates the version, lengths, palette size, range of every index, and existence of global `BlockId` values. A corrupt section returns an error identifying the section; silently substituting air is prohibited. The encoding has a fixed byte order and integrity checks. A checksum detects corruption but does not protect against deliberate tampering.
## 3. Общий шаблон и независимые миры
## 3. Shared templates and independent worlds
Шаблон — неизменяемый снимок состояния мира, а не ссылка на его текущее изменяемое состояние. Внутренние идентификаторы мира, снимка и секции отличаются от пользовательских имён. `WorldInfo.template` может показывать имя источника, но внутренние данные обязаны хранить точный `snapshot_id` и ревизию источника.
A template is an immutable snapshot of a world, not a reference to its current mutable state. Internal world, snapshot, and section IDs are distinct from user-facing names. `WorldInfo.template` may display the source name, but internal data must retain the exact `snapshot_id` and source revision.
Мир содержит ссылку на базовый снимок и собственную таблицу замен секций. Чтение ищет замену мира, затем секцию в снимке, затем возвращает воздух. Явная замена на полностью воздушную секцию обязательна: отсутствие замены означает наследование, поэтому удаление всех блоков шаблона нельзя представлять отсутствующей записью.
A world holds a reference to its base snapshot and its own section override table. A read looks for a world override, then a section in the snapshot, and otherwise returns air. An explicit all-air section override is required: absence of an override means inheritance, so removing all template blocks cannot be represented by a missing entry.
При первом изменении секции из шаблона создаётся новая секция мира. Сама секция шаблона никогда не изменяется. Одинаковые ссылки на неизменяемые секции могут использовать один объект кэша. Возврат секции к точному содержимому шаблона позволяет удалить замену после проверки равенства.
The first edit to a template section creates a new section owned by the world. The template section itself never changes. Identical references to immutable sections can share one cached object. Restoring a section to the exact template content allows its override to be removed after checking equality.
Практическая схема MVP:
Practical MVP design:
1. Неизменяемые секции хранятся по идентификаторам на диске.
2. Снимок содержит дисковый индекс `координата секции → идентификатор секции`.
3. Мир содержит `snapshot_id`, текущую ревизию и дисковый индекс собственных замен.
4. При `create_world(template=source)` снимок берётся строго из одной зафиксированной ревизии источника. Для неизменившегося источника ранее созданный снимок можно переиспользовать.
5. Если нового снимка ещё нет, индекс эффективных секций копируется потоково по ссылкам, внутри согласованной транзакции. Сами блоки и содержимое секций не копируются в RAM или на диск повторно.
1. Immutable sections are stored on disk by ID.
2. A snapshot contains an on-disk index mapping `section coordinate → section ID`.
3. A world contains a `snapshot_id`, its current revision, and an on-disk index of its own overrides.
4. `create_world(template=source)` takes a snapshot from exactly one committed source revision. A previously created snapshot may be reused if the source has not changed.
5. If no snapshot exists for that revision, the index of effective sections is copied incrementally by reference within a consistent transaction. Blocks and section contents are not copied into RAM or duplicated on disk.
Создание нового снимка таким способом может потребовать времени и места, пропорциональных числу ссылок на секции. Обещать `O(1)` для первого fork нельзя. Более сложный постоянный индекс с разделяемыми страницами возможен позже, если измерения покажут необходимость. Не следует заменять эту схему бесконечной цепочкой родительских миров: глубокая цепочка ухудшает чтения и усложняет сборку мусора.
Creating a snapshot this way can take time and space proportional to the number of section references. The first fork must not be promised as `O(1)`. A more complex persistent index with shared pages can be added later if measurements show a need. Do not replace this design with an unbounded chain of parent worlds: deep chains slow reads and complicate garbage collection.
Проверка изоляции: изменить источник после fork, изменить один из двух дочерних миров, перезапустить процесс и убедиться, что три состояния различаются именно ожидаемым образом. Снимок остаётся доступным, даже если источник сброшен или впоследствии удалён.
Isolation check: modify the source after a fork, modify one of two child worlds, restart the process, and verify that all three states differ exactly as expected. The snapshot remains available even if the source is reset or later deleted.
## 4. Ограничение памяти
## 4. Bounding memory
`cache_sections` ограничивает число сохранённых в кэше неизменяемых секций. Ноль явно отклоняется при открытии, как принято в CONTRACT. Для первой реализации используется LRU декодированных секций: массив на 4096 `u32` имеет известный размер 16384 байта полезной нагрузки, а объекты и индекс LRU учитываются дополнительно. Хранение палитр непосредственно в кэше — последующая оптимизация; компактная дисковая кодировка сама по себе не уменьшает декодированный кэш.
`cache_sections` limits the number of immutable sections retained in the cache. Opening with zero is explicitly rejected, as accepted in CONTRACT. The first implementation uses an LRU of decoded sections: an array of 4,096 `u32` values has a known 16,384-byte payload, with objects and the LRU index counted separately. Storing palettes directly in the cache is a later optimization; compact disk encoding alone does not shrink a decoded cache.
Дополнительно контролировать байты кэша: учитывать буфер секции, палитру и метаданные записи, показывать их отдельно от полезной нагрузки. Ключ кэша — идентификатор неизменяемой секции. Кэш только по имени мира и координате легко оставляет устаревшие данные после reset.
Also track cache bytes: account for the section buffer, palette, and entry metadata, and report these separately from payload size. The cache key is the immutable section ID. A cache keyed only by world name and coordinates can easily retain stale data after reset.
Временные буферы транзакции не попадают в бесконечный «грязный» кэш. Обработка секций идёт ограниченными порциями; завершённые записи передаются дисковому транзакционному механизму. Полученный через API `Vec<BlockChange>` уже занимает RAM, поэтому потоковая внутренняя запись не отменяет ограничения размера запроса.
Temporary transaction buffers must not enter an unbounded dirty cache. Sections are processed in bounded batches, with completed writes passed to the disk transaction mechanism. A `Vec<BlockChange>` received through the API already occupies RAM, so streaming internal writes does not remove the need for request size limits.
Историю операций, дедупликацию и индекс секций нельзя загружать целиком при старте. Используется дисковый SQL-индекс с ограниченным кэшем страниц SQLite. Настроить и измерять бюджет страниц и временные данные. Выбор библиотеки сам по себе не доказывает соблюдение бюджета.
Operation history, deduplication records, and section indexes must not be loaded in full at startup. Use an on-disk SQL index with a bounded SQLite page cache. Configure and measure the page and temporary-data budgets. Choosing a library does not by itself prove that a budget is respected.
Метаданные не бесплатны. `registry() -> &[String]` из контракта предполагает реестр в RAM; `list_worlds()` создаёт полный список. Для MVP задать явные ограничения на число миров и состояний и длину строк, отразить их в документации. При выходе за эти границы потребуется API с постраничной выдачей.
Metadata is not free. The contract's `registry() -> &[String]` implies an in-memory registry; `list_worlds()` creates a complete list. Define and document explicit MVP limits on world count, state count, and string length. Exceeding those boundaries will require a paginated API.
Принятые ограничения:
Accepted limits:
- одна операция редактирования — не более 32768 уникальных позиций;
- `read_region` — максимум 262144 ячейки объёма, как в контракте; считать произведение через проверяемую широкую арифметику до выделения памяти;
- имя мира соответствует `[A-Za-z0-9_-]{1,64}`; координаты каждой оси находятся в диапазоне `[-30000000,30000000]`;
- сервер дополнительно ограничивает размер JSON до десериализации, частоту операций, сетевые очереди и число одновременных запросов;
- максимальное количество сущностей и объём очереди изменений задаются отдельно от кэша блоков.
- At most 32,768 unique positions in one edit operation.
- `read_region` covers at most 262,144 cells, as specified by the contract; compute the product with checked wide arithmetic before allocating memory.
- A world name matches `[A-Za-z0-9_-]{1,64}`; coordinates on each axis fall within `[-30000000,30000000]`.
- The server additionally bounds JSON size before deserialization, operation frequency, network queues, and concurrent requests.
- Maximum entity count and change queue size are defined separately from the block cache.
Для ещё не зафиксированного ограничения `operation_id` предлагается от 1 до 128 байт UTF-8. Точные пределы реестра и остальных очередей задаются в реализации и документируются. Размеры должны быть проверены на реальном workload. Ограничение `read_region` относится к объёму области, а не только к числу возвращённых непустых блоков.
For the not-yet-finalized `operation_id` limit, 1 to 128 UTF-8 bytes is proposed. Exact registry and other queue limits are defined and documented in the implementation. Sizes must be tested with a real workload. The `read_region` limit applies to the volume of the region, not just the number of nonempty blocks returned.
## 5. Дисковая история и атомарность
## 5. On-disk history and atomicity
Минимальные логические сущности хранилища: реестр блоков, миры, снимки, ссылки снимков на секции, замены секций миров, неизменяемые секции, операции и изменения операций. История хранит старые и новые состояния затронутых ячеек, тип операции, ревизии, идентификатор и отпечаток нормализованного запроса. История нужна для undo и идемпотентных повторов; обычный журнал сообщений сервера её не заменяет.
The minimum logical storage entities are the block registry, worlds, snapshots, snapshot-to-section references, world section overrides, immutable sections, operations, and operation changes. History stores the previous and new state of each affected cell, operation type, revisions, ID, and a fingerprint of the normalized request. History supports undo and idempotent retries; an ordinary server message log does not replace it.
Дедупликация находится на диске с уникальным ключом `(world_id, operation_id)`. Не держать все идентификаторы операций в `HashMap`. Для поиска отменяемой операции и последующих изменений ячеек нужны дисковые индексы, а не чтение всего журнала на каждый undo.
Deduplication is stored on disk with the unique key `(world_id, operation_id)`. Do not retain all operation IDs in a `HashMap`. Finding the operation to undo and subsequent cell changes requires disk indexes, rather than scanning the entire log for every undo.
Одна успешная мутация атомарно фиксирует:
One successful mutation atomically commits:
1. Новые секции и изменения ссылок мира.
2. Новую ревизию принятой операции, включая no-op.
3. Запись операции, её отпечаток и точный результат для повторной выдачи.
4. Данные истории, необходимые для безопасного undo.
1. New sections and changes to world references.
2. The new revision of the accepted operation, including a no-op.
3. The operation record, its fingerprint, and the exact result to return on replay.
4. History data required for safe undo.
Подтверждение успеха клиенту отправляется после долговечной фиксации всех четырёх частей. Ошибка записи не должна оставлять новую ревизию с прежними блоками или блоки без записи дедупликации. Выделение нового `BlockId` также долговечно: переоткрытие хранилища не перенумеровывает реестр; `air` всегда имеет ID 0.
The client receives a success acknowledgment after all four parts are durably committed. A write failure must not leave a new revision with old blocks, or changed blocks without a deduplication record. Allocating a new `BlockId` is also durable: reopening the store does not renumber the registry, and `air` always has ID 0.
По D008 используется SQLite с WAL и `synchronous=FULL`; собственный WAL не реализуется. Секции остаются собственным версионированным бинарным форматом внутри транзакционного хранилища. Проверить фактическое применение настроек соединения. Не приравнивать запись в буфер ОС к долговечному commit. Гарантии долговечности предполагают исправную файловую систему и устройство, корректно исполняющее запросы синхронизации.
Decision D008 selects SQLite with WAL and `synchronous=FULL`; a custom WAL is not implemented. Sections retain an original, versioned binary format inside the transactional store. Verify that the connection settings actually take effect. Writing to an OS buffer is not a durable commit. Durability guarantees assume a healthy filesystem and device that correctly honor synchronization requests.
На одном пути хранилища допускается один владелец записи. `&mut WorldStore` защищает только конкретный объект Rust: второй процесс или второй независимо открытый объект отклоняется эксклюзивной advisory-блокировкой файла. Блокировка сохраняется весь срок жизни `WorldStore`; сам факт существования lock-файла не означает занятую блокировку. Второе открытие не должно молча порождать две независимые картины метаданных.
A storage path permits one writer. `&mut WorldStore` protects only a particular Rust object: a second process or independently opened object is rejected by an exclusive advisory file lock. The lock remains held for the lifetime of `WorldStore`; the existence of a lock file alone does not mean that the lock is held. A second open must not silently create two independent views of the metadata.
## 6. Ревизии и идемпотентность
## 6. Revisions and idempotency
Ревизия — монотонный номер состояния одного мира. Хотя API использует `u64`, хранение ограничено неотрицательным диапазоном SQLite `i64`: следующая ревизия выше `i64::MAX` возвращает явную ошибку. Оборот к нулю запрещён. Reset не возвращает ревизию к нулю и не позволяет старому запросу случайно пройти проверку нового состояния.
A revision is a monotonically increasing state number for one world. Although the API uses `u64`, storage is limited to the nonnegative range of SQLite `i64`: a next revision above `i64::MAX` returns an explicit error. Wrapping to zero is prohibited. Reset does not return the revision to zero or allow an old request to accidentally pass validation against a new state.
Порядок обработки `edit` и `undo`:
Processing order for `edit` and `undo`:
1. Проверить размеры, формат идентификаторов и нормализовать запрос. Повторяющиеся позиции в `changes` рекомендуется отвергать, чтобы не зависеть от порядка дублей.
2. Найти `(world_id, operation_id)` в долговечной таблице. При совпадающем отпечатке вернуть сохранённый `EditResult`, установив `replayed=true`. Это выполняется до сравнения с текущей ревизией: нормальный повтор после потерянного ответа должен работать.
3. При существующем идентификаторе с другим содержимым вернуть конфликт идемпотентности и ничего не менять.
4. Для новой операции проверить `expected_revision` в той же транзакции, что и изменение. При несовпадении вернуть конфликт с текущей ревизией.
5. Проверить все позиции и `BlockId`, применить и долговечно зафиксировать результат, затем отправить ответ и событие изменения.
1. Validate sizes and ID formats, then normalize the request. Rejecting duplicate positions in `changes` is recommended to avoid dependence on duplicate ordering.
2. Look up `(world_id, operation_id)` in the durable table. If the fingerprint matches, return the stored `EditResult` with `replayed=true`. This happens before comparing against the current revision: a normal retry after a lost response must work.
3. If the ID exists with different content, return an idempotency conflict and change nothing.
4. For a new operation, check `expected_revision` in the same transaction as the mutation. If it differs, return a conflict with the current revision.
5. Validate all positions and `BlockId` values, apply and durably commit the result, then send the response and change event.
Отпечаток включает метод и все его значимые аргументы, включая `expected_revision`; порядок уникальных позиций канонизируется. Область уникальности идентификатора — стабильный внутренний ID мира, а не имя, которое в будущем может быть переиспользовано.
The fingerprint includes the method and all meaningful arguments, including `expected_revision`; the order of unique positions is canonicalized. An ID's uniqueness is scoped to the stable internal world ID, not a name that might later be reused.
Принятая семантика первого этапа: каждая новая успешно принятая edit-операция повышает ревизию, даже при `changed=0`. Такая операция также ставит границу для консервативного undo и сохраняет долговечный результат дедупликации. Точный повтор операции не увеличивает ревизию.
Accepted first-stage semantics: every newly accepted successful edit increments the revision, even when `changed=0`. Such an operation also establishes a boundary for conservative undo and stores a durable deduplication result. An exact replay does not increment the revision.
Повтор возвращает ревизию исходной операции, которая может быть меньше текущей. Клиент не должен откатывать свою текущую ревизию по такому ответу. Ошибка после commit, но до доставки ответа, означает неопределённость для вызывающего кода: безопасный повтор использует тот же идентификатор и те же аргументы.
A replay returns the original operation's revision, which may be lower than the current revision. The client must not roll back its current revision based on that response. An error after commit but before response delivery leaves the caller uncertain; a safe retry uses the same ID and arguments.
Автоматическое удаление истории меняет гарантию дедупликации. До появления явной политики хранения ID и операций история долговечно сохраняется. Уменьшать её срок незаметно нельзя; ограничение RAM достигается дисковым хранением, а не забыванием уже подтверждённых запросов.
Automatically deleting history changes the deduplication guarantee. Until an explicit retention policy exists for IDs and operations, history remains durable. Its retention period must not be shortened silently; RAM is bounded by disk storage, not by forgetting previously acknowledged requests.
## 7. Безопасный undo
## 7. Safe undo
Undo — новая атомарная операция с собственной ревизией и `operation_id`; старый журнал не переписывается. Цель обязана принадлежать тому же миру и содержать реально применённые изменения.
Undo is a new atomic operation with its own revision and `operation_id`; it does not rewrite the old log. Its target must belong to the same world and contain changes that were actually applied.
Принятое консервативное правило MVP (D009): отмена допустима, только если текущая ревизия мира совпадает с результирующей ревизией целевой правки. Последующая правка даже другой ячейки блокирует отмену. Одного сравнения текущего `BlockId` с `after` недостаточно: последовательность «камень → воздух → камень» возвращает тот же блок, но означает чужую более позднюю работу. Выборочная отмена непересекающихся изменений — последующее расширение с отдельными дисковыми индексами происхождения изменений.
The accepted conservative MVP rule (D009) allows undo only when the current world revision matches the target edit's resulting revision. A later edit, even to a different cell, blocks undo. Comparing the current `BlockId` with `after` alone is insufficient: the sequence “stone → air → stone” restores the same block but represents someone else's later work. Selective undo of nonoverlapping changes is a later extension requiring separate on-disk indexes of change provenance.
При конфликте хотя бы одной ячейки отмена целиком отклоняется с описанием конфликта. Частичная отмена не является поведением по умолчанию. Новая отмена уже отменённой операции получает конфликт; точный повтор того же undo возвращает сохранённый результат. Отмену самого undo можно добавить отдельно, после определения семантики; MVP должен явно сообщать об отсутствии поддержки.
A conflict in even one cell rejects the entire undo with a conflict description. Partial undo is not the default behavior. A new undo of an already undone operation receives a conflict; an exact replay of the same undo returns the stored result. Undoing an undo may be added separately after defining its semantics; the MVP must explicitly report that it is unsupported.
Reset ставит барьер истории для отмен: undo операций до reset отклоняется. Это удобно выразить монотонной `epoch` мира, записанной вместе с операциями. Дедупликационные записи прежней эпохи сохраняются: повтор старой операции возвращает старый результат, но не применяет её заново.
Reset establishes an undo history barrier: undo of pre-reset operations is rejected. A monotonically increasing world `epoch`, recorded alongside operations, is a useful representation. Deduplication records from previous epochs remain: replaying an old operation returns its old result without applying it again.
## 8. Fork, reset и жизненный цикл
## 8. Fork, reset, and lifecycle
Fork пинует снимок определённой ревизии источника в одной согласованной операции. Не делать последовательность «узнать ревизию → читать секции без защиты → создать мир»: между действиями источник может измениться. История источника не становится историей дочернего мира; ревизия нового мира может начинаться с нуля при сохранённой ссылке на ревизию снимка.
A fork pins a snapshot of a specific source revision in one consistent operation. Do not use the sequence “read revision → read unprotected sections → create world”: the source can change between steps. Source history does not become child-world history; a new world's revision may start at zero while retaining a reference to the snapshot revision.
Reset возвращает мир к его закреплённому шаблону, а мир без шаблона — к воздуху. Он атомарно удаляет собственные замены, увеличивает ревизию и эпоху, фиксирует операцию reset и инвалидирует соответствующие производные кэши. Снимки, закреплённые другими мирами, не меняются.
Reset returns a world to its pinned template, or to air if it has no template. It atomically removes the world's overrides, increments the revision and epoch, records the reset operation, and invalidates the relevant derived caches. Snapshots pinned by other worlds do not change.
Сервер на reset должен уведомить клиентов о необходимости нового снимка/синхронизации. Событие с пустым `changes` само по себе не удалит уже отображаемые блоки. Сервер также должен согласовать перенос игроков, сущности и состояние арены; ядро блоков не может решать это за игровой слой.
On reset, the server must notify clients that a new snapshot/resynchronization is required. An event with empty `changes` alone will not remove blocks already displayed. The server must also coordinate player relocation, entities, and arena state; the block core cannot make those decisions for the game layer.
Освобождение секций и снимков выполняется только после проверки долговечных ссылок из миров, снимков и нужной истории. Обход связей и удаление идут порциями. Нельзя удалять снимок только потому, что имя его источника больше не существует. До реализации проверенной сборки мусора безопаснее оставлять недостижимые данные на диске и показывать их объём в метриках.
Sections and snapshots may be released only after checking durable references from worlds, snapshots, and required history. Reference traversal and deletion proceed in batches. A snapshot must not be deleted merely because its source name no longer exists. Until verified garbage collection is implemented, retaining unreachable data on disk and reporting its size in metrics is safer.
## 9. Сбои и восстановление
## 9. Failures and recovery
После открытия хранилища проверить версию формата, согласованность метаданных и завершить восстановление до выдачи обслуживающих запросов. Незавершённая транзакция не видна. Завершённая и подтверждённая операция сохраняется после аварийного завершения процесса.
After opening a store, validate the format version and metadata consistency, and complete recovery before serving requests. An incomplete transaction is invisible. A completed, acknowledged operation survives a process crash.
Восстановление WAL выполняет SQLite. Приложение не переписывает и не обрезает его самостоятельно. Ошибки целостности базы, неизвестная версия формата секции и неправильная контрольная сумма требуют явной ошибки и сохранения файлов для диагностики. Не «лечить» такие ошибки удалением данных или созданием пустого мира.
SQLite performs WAL recovery. The application does not rewrite or truncate it itself. Database integrity errors, unknown section format versions, and incorrect checksums require explicit errors and preservation of files for diagnosis. Do not “repair” these errors by deleting data or creating an empty world.
Checkpoint выполняется механизмом SQLite, чтобы авария оставляла согласованное состояние. Приложение не удаляет файлы WAL/SHM вручную. `flush()` возвращает ошибки синхронизации/checkpoint и не маскирует их; его точные гарантии должны быть совместимы с commit-before-ack, а не подменять его.
SQLite performs checkpointing so that a crash leaves a consistent state. The application does not delete WAL/SHM files manually. `flush()` returns synchronization/checkpoint errors without hiding them; its precise guarantees must be compatible with commit-before-ack rather than replacing it.
Обязательные сценарии проверок:
Required verification scenarios:
- остановка процесса до записи, посередине записи, после commit и до ответа;
- повтор операции после каждого такого сбоя;
- исчерпание дискового пространства и отказ записи/синхронизации;
- обрезанный хвост и повреждение середины журнала;
- падение во время snapshot, reset, регистрации блока и checkpoint;
- два открытия одного пути, отрицательные и граничные координаты;
- повтор ID с другим запросом, конфликт ревизии, undo с ABA и undo после reset;
- отказ открытия при кэше 0, вытеснение при 1 и небольшом обычном лимите, последующее переоткрытие.
- Process termination before a write, during a write, and after commit but before the response.
- Replaying the operation after each such failure.
- Exhausted disk space and write/synchronization failures.
- A truncated tail and corruption in the middle of the log.
- Crashes during snapshot, reset, block registration, and checkpoint.
- Two opens of the same path; negative and boundary coordinates.
- Reusing an ID for a different request, revision conflicts, ABA undo, and undo after reset.
- Rejection of a zero-sized cache; eviction with a limit of 1 and with a small ordinary limit, followed by reopening.
Тест с завершением процесса проверяет process-crash recovery, но не имитирует достоверно отключение питания или поведение аппаратного кэша диска. Эти границы нужно указывать рядом с результатом.
A process-termination test verifies process-crash recovery, but does not faithfully simulate power loss or hardware disk-cache behavior. State these boundaries alongside the results.
## 10. Метрики и сравнение с Paper
## 10. Metrics and comparison with Paper
`stats()` должен возвращать стабильные именованные поля с единицами измерения. Полезный минимальный набор: `cache_sections`, `cache_limit_sections`, `cache_payload_bytes`, `cache_hits`, `cache_misses`, `cache_evictions`, `transient_peak_bytes`, `world_count`, `snapshot_count`, `registry_states`, `history_operations`, `storage_bytes`, `wal_bytes`, `dirty_overlay_sections`, `commit_latency_ms`, `recovery_duration_ms`. Счётчик bytes обязан указывать, измеряется ли фактическое выделение или оценка полезной нагрузки.
`stats()` should return stable named fields with units. A useful minimum set is `cache_sections`, `cache_limit_sections`, `cache_payload_bytes`, `cache_hits`, `cache_misses`, `cache_evictions`, `transient_peak_bytes`, `world_count`, `snapshot_count`, `registry_states`, `history_operations`, `storage_bytes`, `wal_bytes`, `dirty_overlay_sections`, `commit_latency_ms`, and `recovery_duration_ms`. A byte counter must state whether it measures actual allocation or estimated payload.
Снаружи измерять RSS/PSS процесса, пиковую RAM, cgroup memory при наличии, CPU, чтение/запись диска, задержку тика и административных операций. Память файлового кэша ОС не следует автоматически объявлять «сэкономленной» или складывать с RSS без объяснения методики.
Measure process RSS/PSS, peak RAM, cgroup memory where available, CPU, disk reads/writes, and tick and administrative-operation latency externally. OS file-cache memory must not automatically be claimed as “saved” or added to RSS without explaining the methodology.
Нагрузочные сценарии:
Load scenarios:
1. Один и тот же шаблон и 1, 10, 100 независимых миров без изменений.
2. Те же миры с одинаковым фиксированным числом изменённых секций, затем с долей изменений 1%, 10% и 100%.
3. Последовательное и случайное движение активной области через карту больше кэша.
4. Длительное редактирование с растущей дисковой историей при постоянном активном наборе секций.
5. Чередование fork/reset и перезапусков, проверка содержимого после каждого этапа.
1. The same template with 1, 10, and 100 independent, unchanged worlds.
2. The same worlds with an identical fixed number of edited sections, then with 1%, 10%, and 100% edited.
3. Sequential and random movement of the active area across a map larger than the cache.
4. Sustained editing with growing on-disk history and a constant active set of sections.
5. Alternating forks/resets and restarts, checking content after each stage.
Фиксировать seed, карту, число миров, игроков/ботов, дистанцию видимости, набор сущностей, длительность прогрева и замера. Сначала сравнивать варианты собственного ядра: прямой массив против палитры, копирование против общего шаблона, разные лимиты кэша. Это помогает связать эффект с конкретным решением.
Record the seed, map, number of worlds, players/bots, view distance, entity set, warmup duration, and measurement duration. First compare variants of the project's own core: direct arrays versus palettes, copying versus a shared template, and different cache limits. This helps attribute an effect to a specific decision.
При сравнении с Paper записать точные версии серверов, Minecraft, Java и Rust, параметры JVM, оборудование, ОС, плагины, способ создания/копирования миров и одинаковый сценарий игроков. Отдельно показывать режим хранения одинаковых блоков и полноценный игровой сценарий. Если Shacraft не выполняет освещение, AI, redstone, генерацию или другие функции сценария Paper, прямо перечислить различия: такой замер не доказывает превосходство при равной функциональности.
When comparing with Paper, record exact server, Minecraft, Java, and Rust versions; JVM settings; hardware; OS; plugins; how worlds were created/copied; and an identical player scenario. Report identical-block storage and complete gameplay scenarios separately. If Shacraft does not perform lighting, AI, redstone, generation, or other functions present in the Paper scenario, list those differences explicitly: that measurement does not demonstrate superiority at equal functionality.
Публиковать исходные команды и сырые результаты, медиану и разброс нескольких прогонов, а также задержки и I/O рядом с RAM. Уменьшение памяти ценой неприемлемого дискового доступа или задержек — измеренный компромисс, а не автоматически успех.
Publish the original commands and raw results, the median and spread across multiple runs, and latency and I/O alongside RAM. Reducing memory at the cost of unacceptable disk access or latency is a measured tradeoff, not automatically a success.
## 11. Проверка контрактов перед следующими этапами
## 11. Contract review before subsequent stages
Часть первоначальных замечаний уже принята в CONTRACT.md и DECISIONS D008–D009; остальные относятся к будущим сетевым этапам:
Some original comments have already been incorporated into CONTRACT.md and DECISIONS D008–D009; the others concern future networking stages:
- Уточнить snapshot/revision в семантике `template`; полезно добавить их в `WorldInfo`.
- Обновить управляющий HTTP-метод `world.reset`, чтобы он тоже требовал уже принятые в Rust API `expected_revision` и `operation_id`. Для retry create/fork определить идемпотентность и ревизию источника.
- Зафиксировать правила no-op и точные пределы строк/реестра; остальных принятых инвариантов это не отменяет.
- Ввести машиночитаемые коды ошибок: неизвестный мир/блок, конфликт ревизии, конфликт ID, конфликт undo, превышение лимита, повреждённое хранилище, отказ записи.
- Уточнить события reset/resync, согласованный снимок `welcome` и доставку изменений после его ревизии; иначе клиент может пропустить изменение между снимком и подпиской.
- Для server inputs явно проверять конечность чисел, границы координат, размер сообщений, частоту запросов, дальность взаимодействия и права на каждый мир. Токен управления не должен попадать в публичные ответы или логи.
- `manifest_hash` подтверждает только заявленную версию ресурсов. Он не доказывает отсутствие модификаций клиента; игровая проверка действий остаётся на сервере.
- Clarify snapshot/revision in `template` semantics; adding them to `WorldInfo` would be useful.
- Update the control HTTP method `world.reset` to require `expected_revision` and `operation_id`, as already accepted in the Rust API. Define idempotency and the source revision for create/fork retries.
- Specify no-op rules and exact string/registry limits; this does not override other accepted invariants.
- Introduce machine-readable error codes: unknown world/block, revision conflict, ID conflict, undo conflict, exceeded limit, corrupt store, and write failure.
- Clarify reset/resync events, a consistent `welcome` snapshot, and delivery of changes after its revision; otherwise, the client can miss a change between the snapshot and subscription.
- Explicitly validate finite numbers, coordinate bounds, message size, request frequency, interaction reach, and per-world permissions for server inputs. The control token must not appear in public responses or logs.
- `manifest_hash` confirms only the declared resource version. It does not prove that the client is unmodified; gameplay validation remains the server's responsibility.
Порядок реализации: компактная секция и её проверки → долговечная атомарная операция и recovery → ревизии/дедупликация/undo → snapshot/fork/reset → ограниченный кэш и метрики → нагрузочные измерения. В каждом этапе сначала сохраняются корректность и восстановление, затем добавляется оптимизация.
Implementation order: compact sections and their tests → durable atomic operations and recovery → revisions/deduplication/undo → snapshot/fork/reset → bounded cache and metrics → load measurements. Each stage preserves correctness and recovery first, then adds optimization.
## Источники по долговечности
## Durability references
[SQLite WAL](https://sqlite.org/wal.html) и [PRAGMA synchronous](https://sqlite.org/pragma.html) описывают синхронизацию WAL при каждом commit в режиме FULL. Это выбранная настройка; корректность нашей схемы и восстановления всё равно проверяется отдельно.
[SQLite WAL](https://sqlite.org/wal.html) and [PRAGMA synchronous](https://sqlite.org/pragma.html) describe WAL synchronization on every commit in FULL mode. This is the selected configuration; the correctness of our schema and recovery still needs separate verification.
+16 -16
View File
@@ -1,17 +1,17 @@
# Единые пакеты расширений
# Unified extension packages
`packages/<directory>/manifest.json` объявляет точные версии, лицензии, зависимости, возможности и ресурсы. При запуске сервер проверяет весь граф зависимостей, размеры, SHA-256, пути и отсутствие symlink. Отсутствующая версия, цикл, неизвестная возможность или изменённый ресурс останавливают запуск. Публикуются только `client` и `common`; файлы `server` не имеют публичного маршрута. Ресурс повторно проверяется при HTTP-чтении.
`packages/<directory>/manifest.json` declares exact versions, licenses, dependencies, capabilities, and resources. At startup, the server verifies the entire dependency graph, sizes, SHA-256 hashes, paths, and absence of symlinks. A missing version, cycle, unknown capability, or modified resource prevents startup. Only `client` and `common` resources are published; `server` files have no public route. Resources are verified again when read over HTTP.
Примеры — `packages/base` и `packages/trampoline`. Все изображения, звук и модели авторские. Данные каталога происходят из официальных отчётов и измерения публичного API Java 26.2; ванильные текстуры и модели в пакеты не входят.
Examples are provided in `packages/base` and `packages/trampoline`. All images, audio, and models are original. Catalog data comes from official reports and measurements through the public Java 26.2 API; packages contain no vanilla textures or models.
Манифест schema 1 содержит:
A schema 1 manifest contains:
- `id`, `version` из трёх числовых частей, `license`;
- `dependencies:[{id,version}]` с точными версиями;
- `capabilities`, например `blocks.define`, `client.texture`, `server.on_jump`;
- `id`, a `version` with three numeric components, and `license`;
- `dependencies:[{id,version}]` with exact versions;
- `capabilities`, such as `blocks.define`, `client.texture`, and `server.on_jump`;
- `resources:[{path,scope,role,sha256,size}]`.
Один ресурс не больше 16 МиБ; пакет не больше 64 МиБ, до 128 ресурсов, до 128 записей в каталоге пакетов. Это ограничения сервера; браузер дополнительно ограничивает суммарно проверяемые публичные ресурсы 128 МиБ на подключение. Определения блоков имеют роль `definitions`, ресурс с этой ролью требует schema 1. Сервер допускает до 4096 дополнительных определений. Блок задаёт `state` как новый идентификатор `namespace:path` без свойств (строчные ASCII-буквы, цифры, `_`, `.`, `-`, дополнительно `/` в path), `color:[r,g,b]`, `collision:[{min,max}]` и необязательный `render` аналогичной формы. Необязательный `opacity` — число 0…1. Если render не указан, используется существующая авторская форма того же состояния или коллизия нового блока. Максимум 64 бокса на каждый набор; допустимый локальный диапазон координат −2…3. Дубликаты определений и переопределение `minecraft:*` отвергаются. Runtime ID назначает сохраняемый реестр; `Game::open` расширяет каталог проверенными определениями до регистрации в WorldStore. Обычный пакетный блок без `behavior` хранится и участвует в физике; `behavior.server_hook: on_jump` связывает его с активным WASM-провайдером.
Each resource is limited to 16 MiB; a package to 64 MiB and 128 resources; the package directory to 128 entries. These are server limits; the browser additionally limits the total verified public resources to 128 MiB per connection. Block definitions use the `definitions` role, and a resource with this role requires schema 1. The server allows up to 4096 additional definitions. A block specifies `state` as a new `namespace:path` identifier without properties (lowercase ASCII letters, digits, `_`, `.`, and `-`, plus `/` in the path), `color:[r,g,b]`, `collision:[{min,max}]`, and an optional `render` of the same form. Optional `opacity` is a number from 0…1. If render is omitted, the existing original shape for that state is used, or the collision shape for a new block. Each set may contain at most 64 boxes; the allowed local coordinate range is −2…3. Duplicate definitions and overrides of `minecraft:*` are rejected. The persistent registry assigns runtime IDs; `Game::open` extends the catalog with verified definitions before registering them in WorldStore. An ordinary package block without `behavior` is stored and participates in physics; `behavior.server_hook: on_jump` binds it to the active WASM provider.
```json
{
@@ -26,18 +26,18 @@
}
```
## Исполнение модуля
## Module execution
В MVP нужен ровно один активный провайдер серверного hook `on_jump`; отсутствие провайдера или два модуля с этой ролью останавливают запуск. Серверный `.wasm` объявляется ресурсом `role: "wasm-on-jump"`, `scope: "server"`; необходима capability `server.on_jump`. Экспорт `on_jump: () -> f32` возвращает импульс прыжка в блоках/с. Сервер вызывает его только при прыжке игрока с блока, который связан с hook через проверенное определение пакета.
The MVP requires exactly one active provider for the `on_jump` server hook; no provider or two modules with this role prevents startup. A server `.wasm` file is declared as a resource with `role: "wasm-on-jump"` and `scope: "server"`; the `server.on_jump` capability is required. The export `on_jump: () -> f32` returns a jump impulse in blocks/s. The server calls it only when a player jumps from a block bound to the hook through a verified package definition.
Исполнение идёт в Wasmi: без импортов, файлов, сети и системных вызовов; до 10 000 единиц fuel на вызов, одна память до 64 КиБ, одна таблица до 128 элементов, один экземпляр. Бинарный модуль не больше 64 КиБ. Результат должен быть конечным числом 0…20; trap или недопустимое значение фиксируется метрикой и даёт обычный прыжок. Выполняемый пример возвращает 10. Тесты проверяют реальный вызов, бесконечный цикл, превышение памяти, попытку импорта и NaN. Отдельный тест создаёт пакет `example:spring`, проверяет его SHA-256, добавляет новый блок в каталог, регистрирует и сохраняет runtime ID, связывает блок с модулем и получает импульс 12 от собственного бинарного WASM. Дубликаты, Minecraft override, недопустимая геометрия, opacity/идентификатор и изменение ресурса после загрузки отвергаются.
Execution uses Wasmi with no imports, files, network access, or system calls; at most 10,000 fuel units per call, one memory up to 64 KiB, one table up to 128 elements, and one instance. The binary module is limited to 64 KiB. The result must be a finite number from 0…20; a trap or invalid value is recorded in a metric and falls back to a normal jump. The working example returns 10. Tests cover an actual invocation, an infinite loop, excessive memory, an attempted import, and NaN. A separate test creates an `example:spring` package, verifies its SHA-256, adds a new block to the catalog, registers and persists its runtime ID, binds the block to the module, and receives an impulse of 12 from its own binary WASM module. Duplicates, Minecraft overrides, invalid geometry, opacity/identifiers, and resource changes after loading are rejected.
Это ограниченный действующий API расширения, а не обещание произвольной совместимости с Forge/Fabric или доступа WASM к полному состоянию мира. Для нового hook необходима явная версия контракта. Spleef в этом MVP реализован серверным режимом Rust с сохраняемыми правилами.
This is a limited, working extension API, with no claim of arbitrary Forge/Fabric compatibility or WASM access to full world state. A new hook requires an explicit contract version. Spleef in this MVP is implemented as a Rust server mode with persistent rules.
## Клиентские ресурсы
## Client resources
`/api/manifest` возвращает публичный список с URL, точной версией, размерами и SHA-256. Браузер скачивает файлы, проверяет размер и хеш **до входа**, затем кладёт в CacheStorage по хешу. При повторном подключении содержимое кэша тоже проверяется. Ошибка хеша удаляет повреждённую запись и запрещает вход. Неподходящий `manifest_hash` сервер отвергает. Публичный хеш не подтверждает, что клиентское приложение не модифицировано.
`/api/manifest` returns the public list with URLs, exact versions, sizes, and SHA-256 hashes. The browser downloads files, verifies their sizes and hashes **before joining**, then stores them in CacheStorage keyed by hash. Cached contents are verified again on subsequent connections. A hash error removes the corrupted entry and prevents joining. The server rejects a mismatched `manifest_hash`. A public hash does not prove that the client application is unmodified.
Базовый пакет даёт пиксельную текстуру; trampoline — собственную текстуру, GLSL-функцию окраски, настройку стиля и короткий синтезированный звук. Они применяются собственным WebGL2-рендерером. В ядре и сервере отсутствует графический движок. Пакет не загружает произвольный привилегированный JavaScript.
The base package provides a pixel texture; the trampoline provides its own texture, a GLSL color function, style settings, and a short synthesized sound. The custom WebGL2 renderer applies them. The core and server contain no graphics engine. Packages do not load arbitrary privileged JavaScript.
Для изменения пакета пересчитайте размер и SHA-256 каждого изменённого ресурса, увеличьте версию и обновите точные зависимости. `scripts/catalog_assets.py` воспроизводимо генерирует встроенные авторские ресурсы и манифесты. Формат ориентирован на будущий лаунчер: лаунчер сможет получить тот же manifest и кэшировать по `(id,version,sha256)`; интеграция конкретного лаунчера в этот репозиторий не входит.
When modifying a package, recalculate the size and SHA-256 of each changed resource, increase the version, and update exact dependencies. `scripts/catalog_assets.py` reproducibly generates the bundled original resources and manifests. The format is designed for a future launcher: it can consume the same manifest and cache by `(id,version,sha256)`; integration with a specific launcher is outside this repository's scope.
+55 -55
View File
@@ -1,80 +1,80 @@
# План разработки
# Development plan
План составлен до реализации. Каждый этап заканчивается воспроизводимым результатом в локальном репозитории. `docs/STATUS.md` обновляется после проверок. Пункт не считается выполненным по наличию интерфейса, заглушки, каталога имён или успешной компиляции.
This plan was written before implementation. Each stage ends with a reproducible result in the local repository. `docs/STATUS.md` is updated after verification. An interface, a stub, a catalog of names, or a successful compilation does not make an item complete.
Текущий прогресс: этапы 0–6 реализованы для локального профиля MVP. Компоненты интегрированы; фактические проверки, пределы нагрузки и ограничения совместимости описаны в STATUS и VERIFICATION. Исходный порядок этапов ниже сохранён.
Current progress: stages 0–6 are implemented for the local MVP profile. The components are integrated; actual checks, load limits, and compatibility limitations are documented in STATUS and VERIFICATION. The original stage order is preserved below.
## Этап 0. Сохранить контекст и проверить проектирование
## Stage 0. Preserve context and review the design
- Записать исходные требования, решения, контракты и критерии приёмки.
- Зафиксировать источники данных совместимости и ограничения лицензий.
- Разделить компоненты так, чтобы можно было независимо разрабатывать хранение, совместимость, сетевой сервер и клиент.
- Согласовать обработку ошибок, координаты, ревизии, ограничения операций и формат диагностики.
- Record the original requirements, decisions, contracts, and acceptance criteria.
- Record compatibility data sources and licensing constraints.
- Separate the components so that storage, compatibility, the network server, and the client can be developed independently.
- Agree on error handling, coordinates, revisions, operation limits, and the diagnostic format.
Выход: документы в `docs/`; список решений без молчаливого сокращения объёма.
Deliverable: documents in `docs/` and a list of decisions, with no silent reduction in scope.
## Этап 1. Ядро и доказуемое управление памятью
## Stage 1. Core and verifiable memory management
- Rust workspace; координаты с корректными отрицательными значениями; реестр канонических состояний блоков.
- Секции 16×16×16: единообразное состояние или палитра и упакованные индексы. Отсутствие отдельного объекта на каждый блок.
- Собственный версионированный формат хранения, ограниченный кэш, выгрузка на диск; операции чтения не изменяют мир.
- Независимые экземпляры общей карты. Изменение/сброс одного экземпляра не влияет на другие; снимок основы имеет чёткую семантику.
- Атомарные правки с журналом восстановления, ревизиями и идемпотентностью. История и undo хранятся на диске с ограниченным потреблением RAM.
- Проверки границ секций, упаковки, изоляции миров, повторов, конфликтов, сохранения и восстановления после сбоя. Измерение хранения общей карты против копий.
- A Rust workspace; coordinates that handle negative values correctly; a registry of canonical block states.
- Sections of 16×16×16 cells: a uniform state or a palette with packed indices. No separate object for each block.
- A custom versioned storage format, bounded cache, and unloading to disk; reads do not modify the world.
- Independent instances of a shared map. Editing or resetting one instance does not affect others; the base snapshot has precise semantics.
- Atomic edits with a recovery journal, revisions, and idempotency. History and undo reside on disk with bounded RAM use.
- Checks for section boundaries, packing, world isolation, retries, conflicts, persistence, and crash recovery. Measurements comparing shared-map storage with copies.
Выход: самостоятельная библиотека и воспроизводимые тесты/измерения. Это ещё не весь MVP.
Deliverable: an independent library and reproducible tests/measurements. This is not yet the complete MVP.
## Этап 2. Сервер и минимальный клиент — сквозной сценарий
## Stage 2. Server and minimal client: an end-to-end scenario
- Сервер владеет миром и симуляцией; фиксированный тик, серверные движение/столкновения и проверка взаимодействий.
- Версионированный протокол: подключение, начальный снимок, изменения блоков, игроки, переход между мирами, ошибки и восстановление подключения.
- Лимиты числа игроков, радиуса мира, сообщений, частоты действий и очередей. Медленный клиент не увеличивает память сервера без ограничения.
- Тестовый клиент: собственный рендерер, камера, управление, блоки, простые сущности, состояния соединения. Сервер остаётся без графики.
- Два независимых клиента видят одинаковые изменения. Перезапуск сохраняет мир. Подключение и выход не оставляют сущности и фоновые задачи.
- The server owns the world and simulation: a fixed tick, server-side movement/collisions, and interaction validation.
- A versioned protocol: connection, initial snapshot, block changes, players, world switching, errors, and reconnection.
- Limits on player count, world radius, messages, action rates, and queues. A slow client cannot increase server memory without bound.
- A test client with a custom renderer, camera, controls, blocks, simple entities, and connection states. The server remains graphics-free.
- Two independent clients see the same changes. Restarts preserve the world. Joining and leaving do not leak entities or background tasks.
Выход: запускаемая локальная сетевая песочница. На первом проходе допустим небольшой набор материалов; это не выполнение требования полного каталога.
Deliverable: a runnable local networked sandbox. A small material set is acceptable on the first pass; it does not satisfy the full-catalog requirement.
## Этап 3. Control API и собственный MCP
## Stage 3. Control API and dedicated MCP
- Общий API чтения, редактирования, истории и диагностики; MCP — отдельный процесс с stdio.
- Поиск материалов, чтение ограниченной области, пакетное строительство и шаблоны, preview/commit, undo с защитой от чужих изменений.
- Ресурсы с системой координат и возможностями; структурированные ответы и понятные ошибки.
- Визуальная обратная связь: снимок с явно указанными типом отображения и ревизией; топографический preview не объявляется снимком игрового клиента.
- Тестовые миры, сущности, управление аренами и метрики. Авторизация управляющего API; токен не попадает в клиентский код и журнал.
- Реальная MCP-сессия: initialize → list → build → inspect/capture → undo; параллельный клиент видит результат.
- A shared API for reading, editing, history, and diagnostics; MCP runs as a separate process over stdio.
- Material search, bounded region reads, batch construction and templates, preview/commit, and undo that protects other edits.
- Resources describing coordinates and capabilities; structured responses and clear errors.
- Visual feedback: an image with an explicit rendering type and revision; a topographic preview is not presented as a game-client screenshot.
- Test worlds, entities, arena management, and metrics. Control API authorization; the token never enters client code or logs.
- A real MCP session: initialize → list → build → inspect/capture → undo; a connected client sees the result.
Выход: законченный цикл автоматизированного строительства с проверкой результата.
Deliverable: a complete automated construction workflow with verification of the result.
## Этап 4. Контент и двусторонняя совместимость
## Stage 4. Content and bidirectional compatibility
- Проверить полный источник каталога именно Java 26.2; генерировать воспроизводимо, хранить происхождение и версию данных.
- Реализовать формы, коллизии и отображение семейств блоков; отдельно учитывать неподдерживаемые особенности. Базовые определения сущностей и сохраняемые свойства.
- Импорт Anvil/NBT по частям с ограниченным бюджетом памяти; обработка измерений и дополнительного NBT.
- Экспорт мира в целевую версию; режим точности и явных замен, sidecar для неподдерживаемых данных, корректное инвалидирование происхождения после правок.
- `.schem` import/export; тестовые fixtures; повторное открытие экспортированных данных независимым читателем и, при доступности целевой игры, самой игрой.
- Verify the complete catalog source specifically for Java 26.2; generate it reproducibly and retain data provenance and version.
- Implement shapes, collisions, and rendering for block families; track unsupported features separately. Base entity definitions and persistent properties.
- Import Anvil/NBT in chunks with a bounded memory budget; handle dimensions and additional NBT.
- Export worlds to the target version; an accuracy mode and explicit substitutions, sidecars for unsupported data, and correct provenance invalidation after edits.
- `.schem` import/export; test fixtures; reopen exports with an independent reader and, when the target game is available, with the game itself.
Выход: проверенный обмен заявленными данными с отчётом покрытия. Полный каталог имён без форм/данных не закрывает этот этап.
Deliverable: verified interchange of the declared data with a coverage report. A complete list of names without shapes/data does not complete this stage.
## Этап 5. Единые пакеты и законченная миниигра
## Stage 5. Unified packages and a complete minigame
- Версионированный манифест с зависимостями, клиентскими/серверными частями, размерами, хешами, лицензиями и возможностями.
- Небольшой собственный базовый набор ассетов. Проверяемая загрузка клиентских ресурсов и кэш; обязательные ресурсы отделены от необязательного качества.
- Первое расширение через единый формат, работающий клиентский и серверный сценарий. Декларативная конфигурация не называется полноценной средой произвольных модулей.
- Spleef: ожидание → отсчёт → игра → выбывание → победитель → сброс. Несколько независимых арен используют общую карту.
- Повторные матчи, отключения, вход во время игры, переход в лобби, сохранение настроек после перезапуска.
- A versioned manifest with dependencies, client/server parts, sizes, hashes, licenses, and capabilities.
- A small set of original base assets. Verified client resource downloads and caching; required resources are separate from optional quality enhancements.
- The first extension through the unified format, with working client and server behavior. Declarative configuration is not described as a full environment for arbitrary modules.
- Spleef: waiting → countdown → play → elimination → winner → reset. Multiple independent arenas use a shared map.
- Repeated matches, disconnects, joining during play, returning to the lobby, and settings that survive restarts.
Выход: друзья могут сыграть законченный матч, а другой разработчик — добавить документированное расширение.
Deliverable: friends can play a complete match, and another developer can add an extension through a documented interface.
## Этап 6. Приёмка, измерения и поставка
## Stage 6. Acceptance, measurements, and delivery
- Проверить все критерии `ACCEPTANCE.md`; отдельный список фактического покрытия и ограничений.
- Измерить RSS/пик памяти, хранение секций, кэши, сетевые очереди, p95/p99 тика, поведение после многократных матчей и перезапуска.
- Сравнение с Paper проводить только при доступном сопоставимом стенде. До этого публиковать собственные числа без заявлений о кратности выигрыша.
- Инструкции запуска, конфигурация MCP, описание API/формата пакетов, лицензии, контрольная сумма исходного архива, Git-коммит.
- Продакшен-публикация и изменение лаунчера — отдельная интеграционная работа после локальной проверки.
- Check every criterion in `ACCEPTANCE.md`; keep a separate record of actual coverage and limitations.
- Measure RSS/peak memory, section storage, caches, network queues, p95/p99 tick time, and behavior after repeated matches and restarts.
- Compare with Paper only when a comparable test setup is available. Until then, publish the project's own figures without claims about multiplicative improvements.
- Startup instructions, MCP configuration, API/package-format documentation, licenses, the source archive checksum, and the Git commit.
- Production publishing and launcher changes are separate integration work after local verification.
Выход: воспроизводимый локальный релиз MVP с честным отчётом, исходным архивом и известными ограничениями.
Deliverable: a reproducible local MVP release with an accurate report, a source archive, and known limitations.
## Рабочий порядок после планирования
## Working order after planning
Сначала этап 1. Параллельно с ним можно готовить протокол и клиент по согласованному контракту, изучать каталог/конвертер. Подключение этих частей, изменения общих интерфейсов и проверки выполняются последовательно. После каждого этапа — сохранить результат; не оставлять единственную копию в одноразовой среде.
Start with stage 1. Protocol and client preparation against the agreed contract, as well as catalog/converter research, can proceed in parallel. Integrating these parts, changing shared interfaces, and verification happen sequentially. Save the result after every stage; do not leave the only copy in a disposable environment.
+20 -21
View File
@@ -1,31 +1,30 @@
# Исходные требования
# Original requirements
Источник: переписка [«Динамическое распределение ресурсов»](https://chatgpt.com/share/6aa7eba7-d0e8-83ed-804a-818e7d94cef5), прочитанная с прокруткой 14 сентября 2026 года, и продолжение в Codex. Этот документ сохраняет требования, а не подтверждает реализацию из старой среды.
Source: the [“Dynamic resource allocation” conversation](https://chatgpt.com/share/6aa7eba7-d0e8-83ed-804a-818e7d94cef5), read in full by scrolling on September 14, 2026, and its continuation in Codex. This document preserves the requirements; it does not validate the implementation from the previous environment.
## Зачем нужен проект
## Project motivation
У Shacraft два сервера на машине с 8 ГБ RAM: выживание на NeoForge (примерно 300 модов, включая Create) и миниигры на Paper 26.2. Исследование динамического распределения памяти привело к самостоятельному проекту воксельного движка. Перенос существующих NeoForge-модов не является требованием первой версии.
Shacraft runs two servers on a machine with 8 GB of RAM: survival on NeoForge (about 300 mods, including Create) and minigames on Paper 26.2. Research into dynamic memory allocation led to a standalone voxel engine project. Porting existing NeoForge mods is not a requirement for the first version.
## Обязательные направления
## Required capabilities
- Самостоятельное открытое ядро на Rust с собственной архитектурой. Низкоуровневые библиотеки допустимы; готовый игровой движок не является основой.
- Серверная RAM — главный измеряемый критерий. Не выдавать Rust, остановку тиков или битовые палитры сами по себе за доказательство экономии относительно Minecraft.
- Независимые ядро, тестовый сервер, тестовый клиент и отдельный собственный MCP. Ядро не зависит от графики, сокетов, MCP и лаунчера.
- Общие неизменяемые карты, независимые изменения экземпляров, выгрузка неактивного состояния, ограничение кэшей, очередей и истории. Один процесс обслуживает несколько миров/арен.
- Полный базовый каталог блоков, состояний и типов сущностей Minecraft Java 26.2. Нужны формы, коллизии и сохраняемые свойства. Полнота каталога и точность механик проверяются отдельно; полная ванильная симуляция не была согласована как обязательная первая реализация.
- Импорт Minecraft → Shacraft и обратный экспорт Shacraft → Minecraft. Основной результат — мир; `.schem` для построек — дополнительный формат. Неизвестные данные сохраняются или явно отражаются в отчёте; тихие потери недопустимы.
- Единая модель расширений: общие определения, серверная и клиентская логика, текстуры, звуки и шейдеры в одном формате пакетов. Сервер объявляет необходимый набор; клиент загружает недостающее, проверяет версии и хеши, использует кэш. Серверные секреты и код с секретами не раздаются клиенту.
- Политика допустимых клиентских модификаций. Сервер проверяет действия и совместимость пакетов. Контрольная сумма, сообщённая самим клиентом, не доказывает неизменность клиента.
- В перспективе — запуск через Shacraft Launcher. Существующая инфраструктура является интеграционной целью, не зависимостью ядра.
- Оригинальные текстуры/звуки/модели Minecraft не включаются в распространяемые файлы. Лицензии контента учитываются отдельно от лицензии кода.
- An independent open-source Rust core with its own architecture. Low-level libraries are allowed; an existing game engine must not form the foundation.
- Server RAM is the main measured criterion. Rust, suspended ticks, or bit-packed palettes alone must not be presented as proof of savings relative to Minecraft.
- Separate core, test server, test client, and a dedicated MCP implementation. The core must not depend on graphics, sockets, MCP, or the launcher.
- Shared immutable maps, independent changes for each instance, unloading of inactive state, and limits on caches, queues, and history. One process serves multiple worlds/arenas.
- The complete base catalog of Minecraft Java 26.2 blocks, states, and entity types. Shapes, collisions, and persistent properties are required. Catalog completeness and mechanical accuracy are checked separately; full vanilla simulation was not agreed as a mandatory first implementation.
- Import from Minecraft to Shacraft and export back from Shacraft to Minecraft. The main output is a world; `.schem` is an additional format for builds. Unknown data must be preserved or explicitly reported; silent loss is unacceptable.
- A unified extension model: shared definitions, server and client logic, textures, sounds, and shaders in a single package format. The server declares the required set; the client downloads missing resources, checks versions and hashes, and uses a cache. Server secrets and code containing secrets must not be distributed to clients.
- A policy for permitted client modifications. The server validates actions and package compatibility. A checksum reported by the client itself does not prove that the client is unmodified.
- Future support for launching through Shacraft Launcher. The existing infrastructure is an integration target, not a core dependency.
- Original Minecraft textures, sounds, and models must not be included in distributed files. Content licenses must be tracked separately from the code license.
## Качественный MCP
## A capable MCP implementation
Minecraft Builder MCP — источник опыта, а не сервер, который нужно переименовать. Нужны самостоятельные инструменты осмотра и поиска, пакетного строительства, сущностей и арен, визуальной проверки и диагностики. Основы: общая Control API, ожидаемые ревизии, идентификаторы операций, конфликтобезопасная отмена, ограниченные ответы, история на диске, ограничения нагрузки и авторизация.
Minecraft Builder MCP is a source of experience, not a server to rename. The project needs its own tools for inspection and search, batch construction, entities and arenas, visual verification, and diagnostics. Foundations: a shared Control API, expected revisions, operation identifiers, conflict-safe undo, bounded responses, on-disk history, load limits, and authorization.
## Что считать фактом
## What counts as evidence
В старом чате заявлялись 1 196 блоков, 158 типов сущностей, семь тестов и частичная реализация. Эти числа необходимо заново проверить по источникам и локальным результатам. Не переносить их в новый отчёт как установленные факты.
Пожелание «в 2–4 раза меньше RAM» обсуждалось как возможная цель, не достигнутый результат. Сравнивать нужно одинаковые карты, загруженные области, игроков и механики, учитывая весь процесс и необходимые сервисы.
The previous conversation claimed 1,196 blocks, 158 entity types, seven tests, and a partial implementation. These figures must be checked again against sources and local results. They must not be carried into a new report as established facts.
The wish to use “2–4 times less RAM” was discussed as a possible target, not an achieved result. Comparisons must use the same maps, loaded regions, players, and mechanics, accounting for the entire process and all required services.
+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.
+22 -22
View File
@@ -1,31 +1,31 @@
# Состояние проекта
# Project status
Обновлено 2026-09-14. Реализован и локально проверен весь согласованный профиль MVP. Рабочая папка: `/home/emil/Desktop/shacraft-core`. Исходный план сохранён до реализации коммитом `ddfcef2`; результаты старой облачной среды не использовались как доказательство.
Updated 2026-09-14. The agreed local MVP profile is implemented and verified. The original plan was committed before implementation as `ddfcef2`; claims from the previous cloud environment were not used as evidence. The verified implementation is commit `b6ba064`, published at [emil28092005/shacraft-core](https://github.com/emil28092005/shacraft-core). Its GitHub Actions run passed. Subsequent documentation changes do not change the runtime.
## Готово
## Implemented
- Самостоятельное ядро Rust: компактные секции, общий ограниченный LRU, долговечные правки и история, immutable snapshots, независимые миры, revision/idempotency, undo/reset.
- Отдельный авторитетный сервер с игровым циклом 20 Гц, проверкой движения/форм/дальности, ограниченными очередями, сохраняемыми настройками и сущностями.
- Собственный браузерный WebGL2-клиент: строительство, каталог, игроки/сущности, чат, миры, загрузка пакетов и диагностика. Нет зависимости от готового игрового движка.
- Настоящий отдельный stdio MCP: 17 инструментов, 4 ресурса, строительный prompt, планы/commit, визуальный PNG и проверка через независимый MCP SDK.
- Полный каталог Java 26.2: 1 196 блоков, 32 366 состояний, 158 сущностей, DataVersion 4903. Коллизии измерены через официальный API, модели авторские; контекстные случаи отмечены.
- Пакеты: точные версии, граф зависимостей, SHA-256/размеры, приватные серверные файлы, проверяемый клиентский кэш. Действующий WASM `on_jump`, пользовательские определения блоков и собственные текстуры/шейдер/звук.
- Spleef: две независимые арены общей карты, отсчёт, выбывание, победитель/ничья, сброс, spectators, сохраняемые правила, восстановление после прерывания. Лобби и галерея 1 197 образцов.
- Anvil и Sponge v3 import/export: типизированный NBT, сохранение оригинала, атомарная публикация, отчёты о потерях/преобразованиях, перенос игровых правок блоков и сущностей.
- Independent Rust core: compact sections, a bounded shared LRU, durable edits and history, immutable snapshots, independent worlds, revisions/idempotency, undo, and reset.
- Separate authoritative server with a 20 Hz game loop, movement/shape/reach validation, bounded queues, and persistent settings and entities.
- Custom browser WebGL2 client: building, a catalog, players/entities, chat, worlds, package downloads, and diagnostics. It does not depend on an existing game engine. The MVP interface currently uses Russian text; repository documentation is in English.
- Separate stdio MCP server: 17 tools, 4 resources, a building prompt, plans/commit, PNG previews, and verification through an independent MCP SDK.
- Complete Java 26.2 catalog: 1,196 blocks, 32,366 states, 158 entity types, DataVersion 4903. Collision shapes are measured through the source API, rendering templates are independently authored, and contextual cases are marked.
- Packages: exact versions, dependency graphs, SHA-256 hashes/sizes, private server files, and a verified client cache. Working WASM `on_jump`, custom block definitions, and original textures/shader/audio.
- Spleef: two independent arenas sharing a map, countdown, elimination, winner/draw, reset, spectators, persistent rules, and recovery after interruption. A lobby and a gallery of 1,197 samples.
- Anvil and Sponge v3 import/export: typed NBT, original preservation, atomic output publication, loss/conversion reports, and transfer of block and entity edits made in Shacraft.
## Проверено
## Verified
84 Rust-теста, 6 JS-тестов, fmt и Clippy без предупреждений; 14 групп реальных HTTP/WebSocket-сценариев, отдельная MCP SDK-сессия, SIGKILL и восстановление. Экспорты прочитаны официальными Java 26.2 codecs и независимым NBT-читателем. Клиент осмотрен в реальном браузере; подтверждены отрисовка, поиск состояний, переход в галерею, догрузка материалов, повторное соединение и кэш ресурсов.
84 Rust tests, 6 JavaScript tests, formatting, and Clippy without warnings; 14 groups of real HTTP/WebSocket scenarios, a separate MCP SDK session, SIGKILL, and recovery. Exports were read by the official Java 26.2 codecs and an independent NBT reader. The client was inspected in a real browser: rendering, state search, gallery navigation, material loading, reconnection, and resource caching were confirmed.
Финальный release-стенд: 100 пустующих экземпляров карты — 50.50 МиБ RSS; 10 движущихся клиентов — максимум 59.65 МиБ RSS/VmHWM, p95 выборки работы тика 7.33–9.54 мс. Это ограниченный локальный профиль, не сравнение с Paper. Команды и доказательства — [VERIFICATION](VERIFICATION.md).
Final release benchmark: 100 idle map instances used 50.50 MiB RSS; 10 moving clients reached a maximum of 59.65 MiB RSS/VmHWM, with sampled tick-work p95 of 7.33–9.54 ms. This is a bounded local profile, not a comparison with Paper. Commands and evidence are in [VERIFICATION](VERIFICATION.md).
## Точные границы
## Exact boundaries
- Это самостоятельная миниигровая платформа с каталогом Minecraft, не полная ванильная симуляция: нет полного AI, redstone, инвентарей или симуляции жидкостей. Формы с зависимостью от контекста помечены; модели не повторяют ванильные ассеты.
- `exact` консервативно отказывает после правок; `best-effort` отражает изменения и выдаёт отчёт. Между Anvil и `.schem` не вся семантика биомов/block entities преобразуется — исходные данные архивируются. Ограничения версий, размеров и контекстов описаны в interop.md.
- История блоков хранится на диске без автоматического удаления. Undo допускает только текущую целевую правку. Preview-планы эфемерны, 5 минут. Метаданные сущностей/правил имеют отдельную ревизию; их API не заявляет журнал идемпотентности ядра.
- Предел игрового пространства с f32-физикой — ±32700; хранение и конвертер поддерживают координаты ядра ±30 миллионов. Память ограничивается несколькими структурами, а не одним магическим RSS-лимитом.
- Проверены Linux x86_64 и локальная нагрузка. Длительный продакшен soak, аппаратное отключение питания, все ОС и игровой плейтест экспорта в запущенном Minecraft не заявляются пройденными.
- Лаунчер, аккаунты, продакшен и существующие серверы — последующая интеграция. Ничего не опубликовано и не развёрнуто на удалённых машинах.
- This is an independent minigame platform with a Minecraft catalog, not a complete vanilla simulation: no full AI, redstone, inventories, or fluid simulation. Context-dependent shapes are marked; models do not reproduce the vanilla assets.
- `exact` conservatively refuses export after edits; `best-effort` reflects changes and produces a report. Anvil and `.schem` conversion does not translate all biome/block-entity semantics; source data is archived. Version, size, and context limits are documented in [interop.md](interop.md).
- Block history is stored on disk without automatic deletion. Undo accepts only the current target edit. Preview plans are ephemeral and expire after five minutes. Entity/rule metadata has its own revision; its API does not claim the core's idempotency journal.
- The playable range with f32 physics is ±32700; storage and conversion support the core's ±30 million coordinates. Several bounded structures control memory use; there is no single hard RSS cap.
- Linux x86_64 and local workloads have been tested. A long production soak, power-loss testing, all operating systems, and an exported-world playtest in a running Minecraft game have not been claimed as passed.
- Launcher integration, accounts, production deployment, and existing servers are future integration work. The source repository is public; the game server has not been deployed to a remote machine.
Контракты компонентов: SERVER.md, MCP.md, CONTENT.md, PACKAGES.md, interop.md. Исходники и release-бинарные файлы упаковывает `scripts/make_release.py`; в архивы не входят токены, локальные миры и Minecraft JAR.
Component contracts: [SERVER](SERVER.md), [MCP](MCP.md), [CONTENT](CONTENT.md), [PACKAGES](PACKAGES.md), and [interop](interop.md). `scripts/make_release.py` packages source and release binaries. Archives exclude tokens, local runtime worlds, and the Minecraft JAR.
+26 -26
View File
@@ -1,8 +1,8 @@
# Проверка локального MVP
# Local MVP verification
Дата: 2026-09-14. Стенд: Linux x86_64, AMD Ryzen 7 1700, Rust/Cargo 1.96.0, Node 22.22.3, Python 3.14.4. Точные версии — [environment.json](verification/environment.json). Исходная ревизия выпуска фиксируется в `RELEASE.json` каждого архива.
Date: 2026-09-14. Test environment: Linux x86_64, AMD Ryzen 7 1700, Rust/Cargo 1.96.0, Node.js 22.22.3, Python 3.14.4. Exact versions are recorded in [environment.json](verification/environment.json). Each release archive records its source revision in `RELEASE.json`. The verified implementation is `b6ba064`; the subsequent English documentation update does not alter runtime files. Raw machine reports and historical command output are preserved as recorded.
## Автоматические проверки
## Automated checks
```bash
bash scripts/verify.sh
@@ -12,49 +12,49 @@ node scripts/check_mcp.mjs --binary target/release/shacraft-server --output arti
node scripts/benchmark_server.mjs --binary target/release/shacraft-server --output artifacts/server-benchmark-final.json
```
`verify.sh` завершился с кодом 0: fmt, Clippy `-D warnings`, **84 Rust-теста** (core 30, content 11, compat 17, MCP 8, server/WASM 18), **6 JS-тестов**, отдельная аварийная проверка хранилища и debug HTTP/WebSocket-сценарий. [Полный журнал](verification/mvp-checks.txt).
`verify.sh` exited with code 0: formatting, Clippy with `-D warnings`, **84 Rust tests** (core 30, content 11, compat 17, MCP 8, server/WASM 18), **6 JavaScript tests**, a separate storage crash check, and debug HTTP/WebSocket scenarios. [Full log](verification/mvp-checks.txt).
Release-прогон прошёл **14 групп**: проверка ресурсов/авторизации, несовместимый manifest, два клиента, авторитетное движение, недостижимая правка, реальные break/place, последовательные ревизии, late join, immutable template/изоляция, чат, события сущностей, reconnect, полный Spleef и reset, удаление отключённых игроков, **SIGKILL → восстановление блоков, свойств сущностей и настроек**. [Отчёт](verification/server-e2e.json).
The release run passed **14 scenario groups**, covering resource/authentication checks, an incompatible manifest, two clients, authoritative movement, unreachable edits, real break/place actions, sequential revisions, late join, immutable templates/isolation, chat, entity events, reconnection, complete Spleef and reset, disconnected-player cleanup, and **SIGKILL followed by recovery of blocks, entity properties, and settings**. [Report](verification/server-e2e.json).
Настоящий MCP SDK 1.30.0 прошёл initialize/notification/ping, 17 schemas, 4 resources, prompt, durable edit/replay/conflict/undo, plan/commit/retry, PNG image content, entities CRUD, настройки, metrics/reset. [Отчёт SDK](verification/mcp-sdk.json). Для воспроизведения установить независимый клиент:
The independent MCP SDK 1.30.0 passed initialize/notification/ping, 17 tool schemas, 4 resources, the prompt, durable edit/replay/conflict/undo, plan/commit/retry, PNG image content, entity CRUD, settings, metrics, and reset. [SDK report](verification/mcp-sdk.json). Install the independent client to reproduce this check:
```bash
npm install --prefix artifacts/mcp-sdk --no-package-lock @modelcontextprotocol/sdk@1.30.0
SHACRAFT_MCP_SDK="$PWD/artifacts/mcp-sdk/node_modules/@modelcontextprotocol/sdk" node scripts/check_mcp.mjs --binary target/release/shacraft-server --output artifacts/mcp-sdk.json
```
В репозитории нет зависимости рабочего клиента от Node/MCP SDK. Они нужны только проверке.
The game client does not depend on Node.js or the MCP SDK; they are verification dependencies. The initial published implementation also passed [GitHub Actions](https://github.com/emil28092005/shacraft-core/actions/runs/34857228288).
## Каталог и совместимость
## Catalog and interoperability
Каталог сравнивается с независимой проекцией официальных отчётов по всем каноническим состояниям, properties/defaults и множеству сущностей. Отдельно проверены геометрия, ориентации плит/ступеней/дверей, контекстные случаи, entity dimensions. Повторный полный генератор отчётов/API и авторских ресурсов воспроизвёл файлы побайтно: [reproducibility](verification/catalog-reproducibility.json).
The catalog is compared with an independent projection of the official reports across every canonical state, property/default, and entity type. Geometry, slab/stair/door orientations, contextual cases, and entity dimensions are checked separately. Repeating the full report/API extraction and original asset generation reproduced the files byte for byte: [reproducibility report](verification/catalog-reproducibility.json).
17 converter-тестов покрывают типизированный NBT, compression modes/external chunks, палитры, negative coordinates, unknown data, offset/3D biomes, удаление stale chest data, original checksums, no-overwrite, invalid input, создание/перемещение/удаление сущностей и отдельный entity fingerprint.
The 17 converter tests cover typed NBT, compression modes/external chunks, palettes, negative coordinates, unknown data, offsets/3D biomes, removal of stale chest data, original checksums, no-overwrite behavior, invalid input, entity creation/movement/deletion, and a separate entity fingerprint.
Официальный Java 26.2 прочитал exact (1 chunk, 3 блока, 1 сущность), edited (2 chunks, 3 блока, 1 сущность) и новый экспорт (2 chunks, 2 блока). nbtlib 2.0.4 проверил Sponge-теги и их числовые типы. [Машиночитаемый результат](verification/interop.json), [команды и ограничения](interop.md). Использовались публичные codecs без запуска Minecraft-сервера и без принятия EULA.
The official Java 26.2 codecs read the exact export (1 chunk, 3 blocks, 1 entity), edited export (2 chunks, 3 blocks, 1 entity), and new export (2 chunks, 2 blocks). nbtlib 2.0.4 checked Sponge tags and their numeric types. [Machine-readable results](verification/interop.json), [commands and limits](interop.md). These checks invoked public codecs without launching the Minecraft game/server; they were not gameplay tests.
## Память и тик
## Memory and tick work
Бюджеты записаны в скрипте **до прогона**: 256 МиБ для процесса с 10 клиентами, p95 выборки работы тика ≤50 мс. Полный каталог включён. Один сервер содержит 5 служебных/демонстрационных миров и 1, 10, затем 100 дополнительных immutable forks лобби. Активные этапы: 10 клиентов в одной области общего мира и в отдельных мирах, движение/прыжок с вводом 20 Гц, по 15 секунд; метрики каждые 100 мс. Затем все клиенты отключаются. Linux VmHWM дополнительно фиксирует пик процесса, включая промежутки между выборками.
Budgets were recorded in the script **before the run**: 256 MiB for the server process with 10 clients, and sampled tick-work p95 ≤50 ms. The full catalog was enabled. One server contained 5 built-in/demo worlds and 1, 10, then 100 additional immutable lobby forks. Active phases ran 10 clients in one shared-world region and in separate worlds, with movement/jump input at 20 Hz for 15 seconds each; metrics were sampled every 100 ms. All clients then disconnected. Linux VmHWM also captured the process peak, including intervals between samples.
Финальный прогон:
Final run:
- 1 / 10 / 100 пустующих forks: максимальный RSS **50.28 / 50.35 / 50.50 МиБ**.
- 10 клиентов в общем мире: RSS/VmHWM **57.00 МиБ**, p95 работы тика **9.54 мс**.
- 10 клиентов в 10 мирах: RSS/VmHWM **59.65 МиБ**, p95 **7.33 мс**.
- После отключения: 0 игроков и 0 активных миров; RSS остаётся **59.65 МиБ** из-за удерживаемого кэша/аллокатора. Нулевое число активных миров не означает нулевой RSS.
- Ограничение кэша выполнено во всех выборках, исходящие очереди и активные миры измерены. Оба заранее заданных бюджета пройдены.
- 1 / 10 / 100 idle forks: maximum RSS **50.28 / 50.35 / 50.50 MiB**.
- 10 clients in one shared world: RSS/VmHWM **57.00 MiB**, tick-work p95 **9.54 ms**.
- 10 clients in 10 worlds: RSS/VmHWM **59.65 MiB**, p95 **7.33 ms**.
- After disconnect: 0 players and 0 active worlds; RSS remained **59.65 MiB** because of retained cache/allocator memory. Zero active worlds does not mean zero RSS.
- The cache limit was respected in every sample; outgoing queues and active worlds were measured. Both budgets set before the run passed.
[Полные фазы и исходные выборки](verification/server-benchmark.json). p95 рассчитан по выборке последней работы тика, не по сетевой задержке и не по всей непрерывной последовательности тиков. Это короткий локальный тест движения; нагрузка ванильных механик, тысячи игроков и бесконечные пользовательские миры не включены. С Paper/NeoForge результат не сравнивался.
[Full phases and raw samples](verification/server-benchmark.json). The p95 is calculated from samples of the last tick's work, not network latency or the complete continuous sequence of ticks. This is a short local movement test; vanilla simulation workloads, thousands of players, and unbounded user worlds are not included. No comparison with Paper/NeoForge was performed.
Отдельный storage benchmark этапа 1 сохраняется в [storage-benchmark.json](verification/storage-benchmark.json): 256 уникальных секций, кэш 8, 100 forks, обход сверх кэша и независимые edit/reset. После создания forks число immutable blobs осталось 256. Это синтетический профиль ядра с двумя состояниями, отдельный от полного сервера.
The separate stage-one storage benchmark is preserved in [storage-benchmark.json](verification/storage-benchmark.json): 256 unique sections, a cache of 8, 100 forks, traversal beyond cache capacity, and independent edit/reset operations. The immutable blob count remained 256 after fork creation. This is a synthetic core profile with two block states, separate from the full server benchmark.
## Браузер и поставка
## Browser and distribution
[Браузерный протокол проверки](verification/browser.md) фиксирует реальные снимки/DOM, каталог, неполные формы, сущности, чистое подключение без полного registry, галерею, повторное соединение и проверенный ресурсный кэш. На этом стенде наблюдались 144 FPS; переносить это число на другие устройства нельзя.
The [browser verification record](verification/browser.md) describes real screenshots/DOM inspection, the catalog, partial shapes, entities, a fresh connection without the full registry, the gallery, reconnection, and the verified resource cache. This setup showed 144 FPS; that number should not be extrapolated to other devices.
`python3 scripts/make_release.py` и вариант `--binaries` создают архив из чистого Git-коммита, добавляют `RELEASE.json` с SHA-256 каждого файла и проверяют каждый файл при повторном чтении архива. Соседний `.sha256` проверяет весь архив. Поставка проверяется повторной распаковкой, offline Cargo-проверкой исходников и запуском извлечённого Linux-бинарного файла с ресурсами из архива. Итоговый журнал упаковки находится рядом с архивами в `artifacts/`.
`python3 scripts/make_release.py` and its `--binaries` variant create an archive from a clean Git commit, add `RELEASE.json` with each file's SHA-256, and verify every file by rereading the archive. An adjacent `.sha256` file checks the entire archive. The `b6ba064` source and Linux binary archives were extracted again, every manifest entry was verified, an offline Cargo source check passed with cached dependencies, and the extracted Linux server started successfully using resources from its archive. Its health endpoint, default worlds, client page, and public resource hashes were verified. The packaging and extraction verification reports are stored alongside the local archives under `artifacts/`.
## Границы приёмки
## Acceptance boundaries
Основные рубежи A-CORE/SERVER/CLIENT/MCP/SPLEEF подтверждены перечисленными тестами и браузерным осмотром. B-CONTENT, B-PACKAGES, B-INTEROP, B-PERSISTENCE выполнены в документированном профиле. B-MEMORY подтверждён указанной нагрузкой, а не произвольным масштабом. Более широкие пункты исходного ACCEPTANCE (долгий soak, все игровые контексты Minecraft, все варианты внешних миров и реальный Minecraft-плейтест) не объявляются пройденными. Заявления о полной ванильной симуляции, аппаратной отказоустойчивости или экономии относительно Paper отсутствуют.
The primary A-CORE/SERVER/CLIENT/MCP/SPLEEF milestones are supported by the tests and browser inspection listed above. B-CONTENT, B-PACKAGES, B-INTEROP, and B-PERSISTENCE are implemented within the documented profile. B-MEMORY is supported by the specified workload, not arbitrary scale. The broader items in the original [ACCEPTANCE](ACCEPTANCE.md) document (a long soak, all Minecraft gameplay contexts, all external-world variants, and a real Minecraft playtest) are not claimed as passed. There is no claim of complete vanilla simulation, hardware fault tolerance, or memory savings relative to Paper.
+39 -39
View File
@@ -1,77 +1,77 @@
# Interchange MVP: Java 26.2 и Sponge v3
# Interchange MVP: Java 26.2 and Sponge v3
`shacraft-compat` — отдельная Rust-библиотека и автономная CLI. Она действительно переносит состояния блоков в `WorldStore`: браузер, Control API и MCP редактируют импортированные данные, а экспорт читает текущие секции. Исходный мир хранится отдельно на диске с SHA-256. Возврат оригинала без изменений является отдельным проверенным режимом.
`shacraft-compat` is a separate Rust library and standalone CLI. It transfers block states into `WorldStore`: the browser, Control API, and MCP edit the imported data, and export reads the current sections. The source world is preserved separately on disk with SHA-256 hashes. Returning the unchanged original is a separate, verified mode.
Целевая версия: **Minecraft Java 26.2, DataVersion 4903**. Библиотека не запускает JVM. Java 25 нужна только воспроизводимой проверке и генератору собственных тестовых сохранений.
Target version: **Minecraft Java 26.2, DataVersion 4903**. The library does not launch a JVM. Java 25 is needed only for reproducible verification and the generator of original test saves.
## Команды
## Commands
Команды выполняются из корня репозитория. Все выходные пути должны отсутствовать. Каждый экспорт публикует **каталог**, даже экспорт одной постройки: в нём находятся `world.schem` и `conversion-report.json`. Если исходный мир уже содержит файл с этим именем, новый отчёт получает числовой суффикс; исходный файл сохраняется.
Run these commands from the repository root. All output paths must be absent. Every export publishes a **directory**, including exports of a single build: it contains `world.schem` and `conversion-report.json`. If the source world already contains a file with that report name, the new report receives a numeric suffix; the original file is preserved.
```bash
cargo build --release -p shacraft-compat -p shacraft-server
# Импорт остановленной копии Java-мира в новый native store.
# Import a copy of a stopped Java world into a new native store.
target/release/shacraft-compat import-anvil /path/to/java-world data/imported
# Открыть импорт в браузере через сервер; в списке миров выбрать main.
# Open the import in the browser through the server; select main in the world list.
target/release/shacraft-server --data data/imported --listen 127.0.0.1:4000
# После остановки сервера: все импортированные измерения вместе.
# After stopping the server: export all imported dimensions together.
target/release/shacraft-compat export-anvil data/imported artifacts/return-exact
target/release/shacraft-compat export-anvil data/imported artifacts/return-edited --mode best-effort
# Новый мир Shacraft: полноценный каталог сохранения Java 26.2.
# New Shacraft world: a complete Java 26.2 save directory.
target/release/shacraft-compat export-anvil data artifacts/new-java-world --world lobby --mode best-effort
# Sponge v3; Offset переносится в координаты native мира.
# Sponge v3; Offset is applied to native world coordinates.
target/release/shacraft-compat import-schem /path/to/build.schem data/build --world main
target/release/shacraft-compat export-schem data/build artifacts/build-edited --mode best-effort
# Экспорт ограниченного объёма нового native мира; границы включительные.
# Export a bounded volume from a new native world; bounds are inclusive.
target/release/shacraft-compat export-schem data artifacts/build --world lobby --min=-16,-1,-16 --max=16,15,16
```
CLI печатает отчёт JSON в stdout, ошибки — JSON в stderr и ненулевой exit code. Конвертация выполняется offline: `WorldStore` удерживает ту же блокировку единственного писателя, что сервер, поэтому параллельное редактирование не смешивает ревизии в одном экспорте. Сам исходный Java-мир должен быть остановленной копией: изменения размера/времени файла во время копирования обнаруживаются, но это не заменяет согласованный backup работающего Minecraft.
The CLI prints a JSON report to stdout; errors produce JSON on stderr and a nonzero exit code. Conversion runs offline: `WorldStore` holds the same single-writer lock as the server, preventing concurrent edits from mixing revisions within one export. The source Java world must itself be a copy of a stopped world: changes to file size/timestamps during copying are detected, but this does not replace a consistent backup of a running Minecraft instance.
## Что реализовано
## Implemented features
- Big-endian NBT: все 12 payload-типов, числовые разрядности, float/double bit patterns, signed arrays, Java modified UTF-8/CESU-8, Unicode, тип элемента пустого списка и неизвестные compound-поля. Duplicate compound keys, невозможные длины, превышение глубины и лишние распакованные байты отклоняются.
- Anvil: `level.dat`, обычные измерения, `dimensions/<namespace>/<path>`, секционные палитры `Name`/`Properties`, современные непересекающие 64-битную границу индексы, отрицательные координаты, единообразные секции, биомы. Чтение gzip, zlib, raw и LZ4Block с checksum, включая внешние `c.x.z.mcc`. Запись zlib и внешний payload для chunk более 255 секторов.
- Исходные `entities`, `block_entities`, POI, биомы, inventories, playerdata, datapacks, неизвестные поля и произвольные обычные файлы сохраняются на диске. Отдельные entity region-файлы действительно читаются для серверного представления, а не только копируются.
- Sponge v3: `Blocks`, sparse palette indices и varints, block entities, сущности, полный 3D-контейнер биомов, размеры, Offset, Metadata и неизвестные теги. Контейнер `Schematic` вложен в корневой NBT compound согласно спецификации.
- Новый Anvil-мир использует собственный маленький шаблон сохранения, созданный public API Java 26.2. В 26.2 параметры генерации и game rules находятся в `data/minecraft/world_gen_settings.dat` и `game_rules.dat`; экспорт включает эти файлы. Генератор — пустой flat overworld, creative, три стандартных измерения, биом plains в новых секциях, высота редактируемого экспорта −64…319.
- Big-endian NBT: all 12 payload types, numeric widths, float/double bit patterns, signed arrays, Java modified UTF-8/CESU-8, Unicode, the element type of an empty list, and unknown compound fields. Duplicate compound keys, impossible lengths, excessive depth, and trailing decompressed bytes are rejected.
- Anvil: `level.dat`, standard dimensions, `dimensions/<namespace>/<path>`, section palettes using `Name`/`Properties`, modern indices that do not cross 64-bit boundaries, negative coordinates, uniform sections, and biomes. Reads gzip, zlib, raw, and LZ4Block with checksum, including external `c.x.z.mcc` files. Writes zlib and an external payload for chunks larger than 255 sectors.
- Original `entities`, `block_entities`, POI, biomes, inventories, playerdata, datapacks, unknown fields, and arbitrary regular files are preserved on disk. Separate entity region files are parsed for the server representation, not merely copied.
- Sponge v3: `Blocks`, sparse palette indices and varints, block entities, entities, the full 3D biome container, dimensions, Offset, Metadata, and unknown tags. The `Schematic` container is nested in the root NBT compound as specified.
- New Anvil worlds use a small original save template created through the public Java 26.2 API. In 26.2, generation settings and game rules reside in `data/minecraft/world_gen_settings.dat` and `game_rules.dat`; export includes these files. Generation uses an empty flat overworld, creative mode, three standard dimensions, the plains biome in new sections, and an editable export height of −64…319.
## Сущности между MCP и файлами мира
## Entities between MCP and world files
Импорт создаёт совместимый `server.sqlite3`, таблица `metadata(id,json)`. До 4 096 сущностей становятся доступны через сервер и MCP с исходными UUID, типом, координатами и поворотом. Остальные сущности, неподходящие координаты и неподдерживаемые записи остаются в оригинале и отмечаются `preserved`; они не превращаются в пропавшие данные.
Import creates a compatible `server.sqlite3` with the table `metadata(id,json)`. Up to 4,096 entities become available through the server and MCP with their original UUIDs, types, coordinates, and rotations. Remaining entities, unsuitable coordinates, and unsupported records stay in the original and are marked `preserved`; the data is not discarded.
Исходный типизированный NBT каждой редактируемой сущности находится в `compat/entities/<uuid>.nbt`; его хеш закреплён в provenance. `compat/native-entities.json` содержит исходное серверное представление. Экспорт отдельно сравнивает fingerprint сущностей и ревизии блоков, поэтому перемещение сущности без правки блоков также отклоняет `exact`.
Each editable entity's original typed NBT is stored in `compat/entities/<uuid>.nbt`; its hash is pinned in the provenance record. `compat/native-entities.json` contains the original server representation. Export compares entity fingerprints and block revisions separately, so moving an entity without editing blocks also causes `exact` to refuse the export.
`best-effort` применяет создание, удаление и перемещение сущностей между chunks/regions и измерениями, а также yaw в радианах из серверного API. Явно поддерживаются свойства `Health`, `CustomName`, `NoGravity`, `Invisible`, `Invulnerable`, `Glowing`, `Silent`, `CustomNameVisible` с соответствующими числовыми/строковыми/логическими типами. Прочие свойства JSON сохраняются в `shacraft-native-entities*.json` и получают `entity_property_unmapped`; они не выдаются за vanilla NBT. Оригинальный NBT сохраняет остальные поля. AI, passengers, leash и связанные UUID не симулируются и не получают обещания точной семантики после перемещения.
`best-effort` applies entity creation, deletion, and movement between chunks/regions and dimensions, as well as yaw in radians from the server API. The properties `Health`, `CustomName`, `NoGravity`, `Invisible`, `Invulnerable`, `Glowing`, `Silent`, and `CustomNameVisible` are explicitly supported with their corresponding numeric/string/boolean types. Other JSON properties are preserved in `shacraft-native-entities*.json` and reported as `entity_property_unmapped`; they are not presented as vanilla NBT. The original NBT retains its other fields. AI, passengers, leashes, and linked UUIDs are not simulated, and their exact semantics after movement are not guaranteed.
## Exact и best-effort
## Exact and best-effort
`exact` использует DataVersion 4903 и тот же формат, что источник. Пока **любая новая ревизия блоков или изменённое серверное представление сущностей** консервативно запрещает точный возврат исходного мира/постройки. Это касается даже отменённой правки, восстановившей те же блоки: ревизия не возвращается назад. Без правок все исходные файлы побайтно идентичны после проверки SHA-256.
`exact` uses DataVersion 4903 and the same format as the source. Currently, **any new block revision or changed server entity representation** conservatively prevents an exact return of the original world/build. This includes an undone edit that restored the same blocks: revisions do not go backward. With no edits, all source files remain byte-identical after SHA-256 verification.
Для нового native мира `exact` поддерживает представимый Sponge v3. Создание нового Anvil-окружения и межформатное преобразование требуют `best-effort`, поскольку свет и производные данные нуждаются в восстановлении Minecraft. Режим не содержит скрытых замен блоков. Неизвестный namespace остаётся в палитре и получает `unsupported`: целевому Minecraft нужен соответствующий мод, иначе он может заменить неизвестный блок воздухом.
For a new native world, `exact` supports representable Sponge v3 data. Creating a new Anvil environment and converting between formats require `best-effort`, because lighting and derived data need rebuilding by Minecraft. This mode makes no hidden block substitutions. Unknown namespaces remain in the palette and are marked `unsupported`: the target Minecraft installation needs the corresponding mod, or it may replace an unknown block with air.
В изменённых Anvil chunks экспорт обновляет палитры/блоки, удаляет сохранённые light arrays и heightmaps, устанавливает `isLightOn=false`, удаляет устаревшие block entities и scheduled ticks непосредственно в изменённых координатах, инвалидирует POI record изменённого chunk. Все эти действия перечислены в отчёте, оригиналы находятся в `shacraft-source-sidecar*`. Это проверенный профиль сериализации и инвалидации; прохождение полной игровой симуляции света/POI не заявляется.
In edited Anvil chunks, export updates palettes/blocks, removes saved light arrays and heightmaps, sets `isLightOn=false`, removes stale block entities and scheduled ticks at the edited coordinates, and invalidates the edited chunk's POI record. The report lists all these actions, and originals remain in `shacraft-source-sidecar*`. This is a verified serialization and invalidation profile; a complete in-game lighting/POI simulation pass is not claimed.
При экспорте между `.schem` и Anvil переносится блоковая модель и явный entity bridge. Биомная сетка, block entities и произвольные metadata разных форматов пока архивируются без преобразования и получают `cross_format_opaque_data`. Оригинал находится рядом с результатом. Неподдерживаемые версии не мигрируют через DataFixer: `exact` отказывает, а `best-effort` сохраняет исходный DataVersion и диагностирует непроверенную схему.
Conversion between `.schem` and Anvil transfers the block model and uses the explicit entity bridge. Biome grids, block entities, and arbitrary metadata from different formats are currently archived without translation and reported as `cross_format_opaque_data`. The original is retained alongside the result. Unsupported versions are not migrated through DataFixer: `exact` refuses them, while `best-effort` preserves the source DataVersion and reports the unverified schema.
## Ограничения ресурсов и публикация
## Resource limits and publication
- Не более 16 MiB распакованного NBT на chunk/постройку, глубина 64, до 1 000 000 NBT nodes. Это лимиты входных данных, не обещание 16 MiB RSS: Rust-структуры и строки занимают дополнительную память.
- Sponge: максимум 262 144 вокселя; Anvil обрабатывается по одному chunk, экспортная очередь координат находится на диске, страницы секций — не более 4 096 ключей. Кэш ядра конвертера — 32 секции плюс ограниченный SQLite cache.
- Entity bridge: 4 096 записей, до 16 KiB properties на сущность, ограничение сериализованного metadata 8 MiB (импортируемый entity subset ограничен 6 MiB с запасом для настроек сервера). Избыточные исходные сущности сохраняются без загрузки всех записей в серверную RAM.
- До 1 000 подробных issue в отчёте; `omitted_issues` явно считает оставшиеся события. До 256 импортированных измерений, 1 000 000 файлов, 8 GiB на исходный файл и 1 TiB суммарного источника. Symlinks, специальные файлы, выход из каталога, вложенный в исходный мир destination и повреждённые region headers отклоняются.
- Импорт строит весь новый native store, metadata и provenance в соседнем временном каталоге. Экспорт тоже использует staging. Файлы и каталоги синхронизируются, публикация — Linux `renameat2(RENAME_NOREPLACE)` и fsync родителя. Конвертер никогда не перезаписывает существующий destination и не меняет исходный Java-мир.
- При штатной ошибке staging удаляется; после SIGKILL может остаться непубликованный `.shacraft-convert-*`. Повторный импорт безопасно начинается заново. Возобновление с последнего chunk после аварии ещё не реализовано. Нужен запас диска: исходный архив плюс native DB, а изменённый экспорт сохраняет ещё одну полную копию исходника.
- At most 16 MiB of decompressed NBT per chunk/build, depth 64, and up to 1,000,000 NBT nodes. These are input limits, not a promise of 16 MiB RSS: Rust structures and strings require additional memory.
- Sponge: at most 262,144 voxels. Anvil processes one chunk at a time, keeps the export coordinate queue on disk, and pages section keys in batches of at most 4,096. The converter's core cache holds 32 sections, plus a bounded SQLite cache.
- Entity bridge: 4,096 records, up to 16 KiB of properties per entity, and an 8 MiB serialized metadata limit. The imported entity subset is limited to 6 MiB to leave room for server settings. Excess source entities are preserved without loading all records into server RAM.
- At most 1,000 detailed issues in the report; `omitted_issues` explicitly counts the remaining events. Limits: 256 imported dimensions, 1,000,000 files, 8 GiB per source file, and 1 TiB for the complete source. Symlinks, special files, directory escapes, a destination nested inside the source world, and corrupt region headers are rejected.
- Import builds the complete new native store, metadata, and provenance in an adjacent temporary directory. Export also uses staging. Files and directories are synchronized; publication uses Linux `renameat2(RENAME_NOREPLACE)` and fsync of the parent directory. The converter never overwrites an existing destination or changes the source Java world.
- On an ordinary error, staging is removed; SIGKILL can leave an unpublished `.shacraft-convert-*` directory. Retrying an import safely starts over. Resuming from the last chunk after a crash is not yet implemented. Allow enough disk space for the source archive plus the native DB; an edited export retains another complete copy of the source.
`.schem` v2, legacy `.schematic`, vanilla structure `.nbt`, произвольные повороты/миграции версий и полная ванильная симуляция не включены в этот профиль. Они не распознаются как v3 по расширению файла.
`.schem` v2, legacy `.schematic`, vanilla structure `.nbt`, arbitrary rotations/version migrations, and complete vanilla simulation are outside this profile. They are not treated as v3 based on the filename extension.
## Воспроизводимая проверка
## Reproducible verification
```bash
cargo test -p shacraft-compat
@@ -81,8 +81,8 @@ artifacts/compat-venv/bin/pip install nbtlib==2.0.4
artifacts/compat-venv/bin/python scripts/compat_verify.py
```
Для последней команды нужен pinned JAR/JDK из `scripts/catalog_generate.py`; альтернативный JDK передаётся `--java-bin /path/to/jdk25/bin`. Скрипт проверяет SHA-1 JAR, компилирует `compat_java.java`, проверяет оригинальный, изменённый и новый Rust-экспорт через **официальные `NbtIo`, `RegionFile`, `SerializableChunkData`, `PrimaryLevelData`, `WorldGenSettings`**. Независимый `nbtlib 2.0.4` сравнивает типизированные Sponge-теги. Результат и Java logs сохраняются в `artifacts/compat-verification-*/verification.json`.
The last command needs the pinned JAR/JDK from `scripts/catalog_generate.py`; pass an alternative JDK with `--java-bin /path/to/jdk25/bin`. The script checks the JAR's SHA-1, compiles `compat_java.java`, and validates original, edited, and new Rust exports through the **official `NbtIo`, `RegionFile`, `SerializableChunkData`, `PrimaryLevelData`, and `WorldGenSettings`**. Independent `nbtlib 2.0.4` checks compare typed Sponge tags. Results and Java logs are saved under `artifacts/compat-verification-*/verification.json`.
Проверка 14 сентября 2026: 17 Rust-тестов и clippy прошли; Java прочитал exact 1 chunk / 3 блока, edited 2 chunks / 3 блока, new 2 chunks / 2 блока. Плюс тесты всех четырёх compression modes, внешнего большого chunk, границ палитр, отрицательных координат, entities move/create/remove, отказа exact после entity edits, checksum и no-overwrite. Java-проверка использует codecs, **не запускает сервер, не принимает EULA и не является игровым плейтестом**.
Verification on September 14, 2026: 17 Rust tests and clippy passed; Java read exact 1 chunk / 3 blocks, edited 2 chunks / 3 blocks, and new 2 chunks / 2 blocks. Checks also cover all four compression modes, a large external chunk, palette boundaries, negative coordinates, entity move/create/remove, refusal of exact after entity edits, checksum validation, and no-overwrite behavior. Java verification uses codecs **without launching the Minecraft game/server or accepting its server startup prompt; it is not an in-game playtest**.
Первичные источники: [Sponge v3 specification](https://github.com/SpongePowered/Schematic-Specification/blob/master/versions/schematic-3.md), [WorldEdit AnvilChunk18](https://github.com/EngineHub/WorldEdit/blob/dca10737fe81bd81bb6a096e1801cc2d94f1793b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java), [lz4-java block stream](https://github.com/lz4/lz4-java/blob/master/src/java/net/jpountz/lz4/LZ4BlockInputStream.java). Runtime реализация написана самостоятельно; код Minecraft и оригинальные игровые ресурсы не включены.
Primary sources: [Sponge v3 specification](https://github.com/SpongePowered/Schematic-Specification/blob/master/versions/schematic-3.md), [WorldEdit AnvilChunk18](https://github.com/EngineHub/WorldEdit/blob/dca10737fe81bd81bb6a096e1801cc2d94f1793b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java), [lz4-java block stream](https://github.com/lz4/lz4-java/blob/master/src/java/net/jpountz/lz4/LZ4BlockInputStream.java). The runtime implementation is original; Minecraft code and original game assets are not included.
+11 -11
View File
@@ -1,14 +1,14 @@
# Браузерная проверка 2026-09-14
# Browser verification — 2026-09-14
Проверялся реальный Codex In-app Browser на `http://127.0.0.1:4000` через CUA. API-тесты проводились отдельными HTTP/WebSocket-процессами.
The real Codex in-app browser was tested at `http://127.0.0.1:4000` through CUA. Separate HTTP/WebSocket processes performed the API tests.
- Чистое открытие страницы: manifest, 8 проверенных ресурсов, вход в lobby, собственный WebGL2-рендер без ошибки инициализации.
- Лобби видно на реальном снимке: пиксельная площадка, световые столбы, арка, вода, trampoline, небо, солнце, HUD.
- Каталог открыл 32 367 состояний; поиск `minecraft:oak_slab` вернул 6 вариантов с точными type/waterlogged. Выбран `type=bottom,waterlogged=false`, быстрый слот сменился на него.
- Диагностика показывала live tick/ack, ревизию, координаты, число блоков, RAM и полезный кэш отдельно. В лобби на стенде наблюдались 144 FPS, 11 920 треугольников, 0 ожидающих секций.
- После остановки и замены серверного процесса открытая страница автоматически переподключилась. Ранее выбранный материал остался выбранным.
- Созданные через Control API сохраняемые сущности пришли в клиент; allay виден на снимке, счётчик сущностей обновился.
- Второй чистый браузерный клиент загрузил финальный протокол **без передачи полного registry**. Hotbar заполнился через поиск каталога; 8 ресурсов повторно прошли проверку из кэша.
- Выбор `gallery` заменил мир. На реальном снимке видны разные кубические и неполные формы, UI не перекрывает весь мир. Диагностика: 1 614 блоков в текущем окне, 7 808 треугольников, 144 FPS, 0 ожидающих секций. Все 1 197 образцов находятся в мире, а не обязательно в одном окне просмотра.
- Fresh page load: manifest, 8 verified resources, lobby entry, and the custom WebGL2 renderer without an initialization error.
- The lobby was visible in a real screenshot: a pixel-textured platform, light pillars, an arch, water, a trampoline, sky, sun, and HUD.
- The catalog opened with 32,367 states. Searching for `minecraft:oak_slab` returned 6 variants with exact type/waterlogged properties. Selecting `type=bottom,waterlogged=false` updated the active quick slot.
- Diagnostics showed live tick/ack, revision, coordinates, block count, RAM, and useful cache payload separately. The lobby on this test machine showed 144 FPS, 11,920 triangles, and 0 queued sections.
- After the server process was stopped and replaced, the open page reconnected automatically. The previously selected material remained selected.
- Persistent entities created through the Control API reached the client; an allay was visible in a screenshot and the entity count updated.
- A second fresh browser client loaded the final protocol **without receiving the full registry**. The hotbar populated through catalog queries; all 8 cached resources passed verification again.
- Selecting `gallery` switched worlds. A real screenshot showed varied cubic and partial shapes, with the UI leaving the world visible. Diagnostics: 1,614 blocks in the current view, 7,808 triangles, 144 FPS, and 0 queued sections. All 1,197 samples exist in the world, but are not necessarily visible in one view.
FPS описывает этот браузер, оборудование, размер окна и точку наблюдения. Это не минимальное требование и не обещание производительности на другом устройстве. Движение, reach, строительство двух клиентов, Spleef, переподключение и аварийная долговечность дополнительно проверены воспроизводимым `scripts/check_server.mjs`.
FPS describes this browser, hardware, viewport size, and viewing position. It is neither a minimum requirement nor a performance promise for another device. Movement, reach, two-client building, Spleef, reconnection, and crash durability were additionally checked by the reproducible `scripts/check_server.mjs` harness.