diff --git a/PLAN.md b/PLAN.md new file mode 100644 index 0000000..0374549 --- /dev/null +++ b/PLAN.md @@ -0,0 +1,368 @@ +# RustNotMC — данные оригинала, решения и план работ + +Файл для перечитывания: после сброса контекста, при передаче работы другому +агенту или при возврате к проекту через месяц. Здесь лежит всё, что нужно +знать, чтобы продолжить, не выясняя заново. + +Порядок работы: сначала этот файл, потом код. + +--- + +## 0. Где мы сейчас + +| модуль | что в нём | состояние | +|---|---|---| +| `rsx-protocol` | формат провода: кадрирование, буфер, рукопожатие, игровые пакеты | рабочий, 22 теста | +| `rsx-auth` | свои аккаунты сервера (PBKDF2, токены, троттлинг) | рабочий, используется только когда лаунчер не настроен | +| `rsx-server-core` | тик-луп, мир (чанки, генерация, сохранение), сессии, вход через лаунчер | рабочий, 49 тестов | +| `rsx-client` | загрузчик модов, API модов, хуки в клиент | рабочий, 128 тестов | +| `game-fork` | форк Minecraft 1.12.2: свой сетевой слой, свой экран входа, свой HUD | собирается чисто, 3275 классов | + +Уже работает целиком: клиент заходит на сервер по токену лаунчера → сервер спрашивает +лаунчер «этот ваш?» → клиент получает мир → чанки приходят и рисуются → +игрок ходит и ломает блоки. + +Не сделано: предметы, инвентарь, крафт, верстаки, изучение чертежей, узлы-ресурсы +(деревья/камни/руда как разрушаемые объекты), постройка баз, нормальная генерация +мира, транспорт на NIO, дальний вид (DistantView). + +--- + +## 1. Данные оригинала (Rust) + +Источники: вики Rust (rust.fandom.com), локальный референс `G:\decompiled-rustex` +(Rust-клон на MC 1.8, обфусцирован), Paper API (jd.papermc.io). + +### 1.1 Камень (Rock) — стартовый предмет + +> «the most basic resource gathering and fighting tool» — инструмент сбора и оружие. + +- Выдаётся **первым предметом в тулбаре** при спавне. Крафтится из 10 камня. +- Прочность **ограниченная**, предмет изнашивается. +- Собирает дерево и камень; ломает бочки; бьёт постройки. +- **Урон по постройкам:** лоза (twig) — **9**, дерево/камень — **0.2**, металл — **0.1**, + бронированные — **0.1**. То есть обычным камнем постройку не сносят. + +Таблица сбора (сколько снимает один удар, сколько нужно ударов, сколько урона): + +| ресурс | доля прочности за удар | ударов до разрушения | урон за удар | +|---|---|---|---| +| дерево | 0.3 | 2 | 10 | +| руда | 0.3 | 2 | 5 | +| животное | 0.0 | 2 | 10 | + +### 1.2 Верстак (Workbench) — 3 уровня + +- Разворачиваемый **предмет**: надо **стоять рядом**, чтобы крафтить. +- Открывает **тех-дерево**: рецепты своего уровня **и ниже**. +- Уровень выше → время крафта короче: **−50%** на один уровень выше, максимум **−75%** + на два уровня выше. +- Рецепты, открытые верстаком, **нельзя передать** другому игроку (в отличие от + чертежей со стола исследований). + +Стоимость и время изготовления: + +| уровень | ingredients | время | где крафтится | +|---|---|---|---| +| 1 | 500 дерева, 100 металла, 50 скрапа | 60 с | — | +| 2 | 500 металла, 20 ХМ, 500 скрапа | 60 с | верстак 1 | +| 3 | 1000 металла, 100 ХМ, 1250 скрапа | 60 с | верстак 2 | + +Что открывает каждый уровень (выборочно, полный список — в вики): + +- **L1:** постройки (пол, решётка, ворота, сетка-фенси, гаражные ворота, мешки с песком, + бойницы, ставни, лестница, окна, калитка), предметы (торговый автомат, верстак для ремонта, + кровать, лампа, стул, холодильник, мишень, **стол исследований**, **верстак 2**), ресурсы + (порох), одежда (футболка, штаны, лонгслив, шахтёрская каска, куртка, рубашка, каска, ведро, + резиновая каска), **инструменты: Salvaged Hammer, Hatchet, Pick Axe** (топор, кирка), + оружие (пистолеты, револьвер, лом, гвоздомёт, дробовик, пистолет-пулемёт, M16, огнемёт, + F1, гранната, мачете, глушитель, фонарь, прицел, коллиматор, 8-кратник), патроны + (пистолетная, высокоскоростная стрела), ловушки (капкан, огнемёт, мина). +- **L2:** бетонный баррикад, клетка, водосборник, металл-баррикад, люк; предметы (большая + печь, дроп-бокс, шкаф, нефтезаводка, прожектор, **верстак 3**); одежда (тяжёлая броня); + инструменты (Salvaged Axe, Salvaged Icepick); оружие (пистолет-пулемёт Python, огнемёт, + дробовик, Thompson, тесак, дульный тормоз, глушитель, длинный меч), патроны (5.56, 12 калибра), + ловушки (автотурель). +- **L3:** каменные врата, бронированные двери, укреплённые окна; **взрывчатка**; тяжёлая броня; + оружие (штурмовая винтовка, bolt action, rocket launcher, MP5A4); боеприпасы; детали + (шестерни, труба, маслёнка, пружина, набор для шитья). + +### 1.3 Стол исследований (Research Table) и чертежи (Blueprints) + +- «to create Blueprints by using Scrap and the item to make the blueprint of, + **which means one has to find the desired item first**». +- Процедура: кладёшь **один** нужный предмет в верхний слот → показывается требуемый + скрап (в нижний слот) → кнопка «Research» → **10 секунд** → в верхнем слоте появляется + **чертёж**, **предмет уничтожается**. +- Прочность предмета на результат не влияет (если предмет не сломан — иначе не работает). +- Исследование **продолжается**, если закрыть интерфейс стола. Звук слышно рядом. +- Скрап: 20 / 75 / 125 / 500 по тирам предмета. +- Сам стол: **200 металла + 20 скрапа**, крафтится **на верстаке 1**, 60 с. +- Столы есть на **монументах** (аэродром, электростанция, спутниковая тарелка, супермаркет, + аванпост) — то есть это вещь, за которой надо **сходить**. +- **Эксперимент на верстаке:** ломаешь 75 / 300 / 1000 скрапа → получаешь **случайный + ещё неизвестный** чертёж уровня этого верстака. Отличие от стола: случайный результат. + +### 1.4 Скрап (Scrap) + +- Выпадает при разрушении **постройек** игроков, а не из ресурсных узлов. +- Тратится на исследование и на крафт верстаков. + +### 1.5 Постройка баз (Rust) + +**Как ставится.** Строительный план (Building Plan, 20 дерева) — **разворачиваемый +предмет**: кладёшь в хотбар, выбираешь, видишь «призрак» объекта; **ПКМ + движение +мышью** перебирает варианты объекта, **ЛКМ** ставит. + +**Два слоя объектов:** + +- **Строительные** (то, из чего база): фундамент (квадратный/треугольный), пол (квадратный/ + треугольный), стена, полустена, низкая стена, **дверной проём**, окно, настенная рамка, + рамка пола, лестница, крыша, столб. +- **Внутренние** (то, что внутри): двери, верстаки, печи, сундуки, торговый автомат, шкаф, + инструментальный шкаф, замки. + +**Ставятся свободно, не по сетке мира.** Снаппятся **внутренние** к уже поставленным +строительным: стены — к **краю фундамента**, полы — к **верхней кромке стены**, двери — **внутрь +дверного проёма**. Правило из вики дословно: «To place walls, select them and aim at the +edge of a foundation. Floors must be placed at the top edge of a wall, and doors must be +placed inside door frames.» + +**Проёмы двух видов:** +- **малый** (дверной проём) — влезает **только одиночная** дверь; +- **большой** — влезают **двойные двери и гаражные**, но **не одиночные**. + +**Уровни (tiers) и прочность:** + +| уровень | прочность | как получить | цена (пример) | +|---|---|---|---| +| Twig (лоза) | **10** | только строительным планом, напрямую | дерево: фундамент 50, стена 50, проём 35, окно 35, пол 25, рамка 25, лестница 50, крыша 50 | +| Wood (дерево) | **250** | **улучшение** из лозы молотком | дерево ×4 | +| Stone (камень) | **500** | улучшение молотком | камень | +| Sheet Metal (лист) | — | улучшение молотком | металл (вдвое дешевле камня, но нужна переплавка) | +| Armored (броня) | **2000** | улучшение молотком | High Quality Metal | + +Двери: деревянная 200 HP, листовая 250 HP, бронедверь 800 HP. Понизить уровень нельзя. + +**Куда можно строить:** почти везде; крутые склоны и неровная земля мешают, фундамент +ставят и под водой. + +**Прочность конструкции (stability):** у постройки есть запас прочности; если он упал в ноль — +объект ломается сразу при установке. Столбы ставят **до** стен, под столбом должен быть +фундамент, и на втором этаже столбы должны быть и снизу. + +**Инструментальный шкаф (Tool Cupboard):** разблокирует постройку **в радиусе 50 м** от +любого фундамента базы, в которой он стоит. «Twig floors can be built, regardless of the +building privileges» — лозу строить можно всегда, улучшать — нельзя. + +**Замки:** ключевой (дерево) и кодовый (100 металла, 4 цифры). Ставятся на двери, на +контейнеры (сундуки, торговый автомат) и на инструментальный шкаф. + +**Гниение (decay):** лоза и дерево теряют здоровье через несколько часов и разваливаются, +камень/металл/броня — через дни. Открытие/закрытие двери с замком сбрасывает таймер гниения. + +### 1.6 Что из этого берём мы + +- Строительные объекты — **наши кастомные предметы** (не блоки мира). +- Ставятся **свободно**, внутренние **снаппятся** к поставленным (сокеты на объектах). +- **Два вида проёмов**: малый (только одиночная дверь) и большой (двойные/гаражные, но не + одиночные). +- Уровни (tier) и прочность — как в Rust, плюс **тег `admin`** (см. п. 2.2) для объектов, + которые нельзя ставить обычному игроку. +- Столб/устойчивость и гниение — **позже**, по необходимости. + +--- + +## 2. Решения по проекту + +### 2.1 Кто такой админ + +**Админ — свойство конкретного сервера, а не проекта.** Проект коммьюнити-френдли: +в разных серверах разные роли и разные права. Роль приходит из лаунчера +(у лаунчера есть `server/roles.py` и роли `ROLE_USER / ROLE_PASS_HOLDER / ROLE_MODERATOR / +ROLE_ELDER / ROLE_CREATOR`). + +### 2.2 Кто что может ставить и ломать + +Правило на **блоке/предмете** (тег `admin`): + +| тег `admin` | кто может ставить/ломать/менять | +|---|---| +| **нет** | **кто угодно**, включая обычных игроков | +| **есть** | **только админы сервера** | + +- Тег `admin` есть, например, у «тестблока» и у всего, что не добавлено в + крафт/изучение/дроп. +- **Режим креатива не даёт прав.** Даже игрок в креативе без админки не может поставить + или сломать блок с тегом `admin`. +- Проверка — **на сервере**. Клиент только показывает или не показывает курсор. + +### 2.3 Ванильные блоки игры + +Мир (карта, монолиты, рельеф) — **не ломается и не строится обычными игроками**: +это работа админов. Игроки строят **нашими кастомными** предметами через наш API. + +### 2.4 Предметы + +- Все предметы игрока — **кастомные, через наш код и наше API** (не ванильные `ItemStack`). +- У предмета: **прочность**, **урон**, **значение bench**. + - `bench = 0` — крафтится сразу. + - `bench = 1` — **изначально недоступен для крафта**, его надо **изучить на верстаке** + (или получить чертёж через стол исследований). +- У предмета есть **класс инструмента** (NONE / PICKAXE / AXE / SWORD / …) и + **класс ресурса**, который он добывает. + +### 2.5 Крафт + +- Как в Rust: **верстаки трёх уровней** (разворачиваемый предмет, надо стоять рядом), + **чертежи** (стол исследований: нужен найденный предмет + скрап), + **эксперименты на верстаке** (случайный чертёж за скрап). +- Знание рецепта — **состояние игрока**, а не свойство предмета. +- Время крафта, множитель от уровня верстака, стоимость скрапа — как в Rust. + +### 2.6 Структуры вместо блоков мира + +Руда, деревья и камни — **не блоки мира, а разрушаемые объекты** (как узлы в Rust): +у них есть прочность, они бьются инструментом и дают дроп. Мир меняют только админы. + +### 2.7 Текстуры + +- Текстуры предметов пока **временные**, взяты из ремейка как заглушки. +- **Пометка: заменить на свои** (см. п. 6). + +--- + +## 3. Архитектура + +### 3.1 Модули + +| модуль | про что | лицензия | +|---|---|---| +| `rsx-client` | загрузчик модов, API модов, хуки в клиент | MIT | +| `rsx-protocol` | формат провода, общий словарь (блоки, формат чанка) | MIT | +| `rsx-plugin-api` | **API серверного контента**: события, реестр предметов, рецепты, роли | MIT (пустой, следующий) | +| `rsx-server-core` | тик-луп, мир, сущности, масштабирование | proprietary | +| `rsx-auth` | свои аккаунты сервера (когда лаунчер не настроен) | proprietary | + +### 3.2 Провод + +- Кадр: `magic "RSX1"`, версия, id пакета, длина, тело. +- Рукопожатие: `Hello → HelloAck → Auth|LauncherAuth → AuthAck → Login → LoginAck`. +- **Вход через лаунчер:** клиент отдаёт токен лаунчера, сервер спрашивает лаунчер + `POST /auth/validate` (у лаунчера такой эндпоинт есть, он же проверяет бан) → + если «свой» — выдаёт свой игровой токен. +- Игровая фаза: `JoinWorld → WorldJoin`, `ChunkData`, `BlockChange`, `PlayerMove`, + `EntitySpawn/Move/Remove`, `BreakProgress`, `SetGameMode`, `Inventory`, `Ping/Pong`. + +### 3.3 Мир + +- Чанк 16×16×256, **палитра по секциям** (4 бита на блок) — плоский массив не годится: + 62 500 чанков × 64 КБ = 4 ГБ. +- Лежат **регионами на диске** (32×32 чанка в файле), в памяти — LRU-кэш. +- Генерация — чистая функция от зерна и координат (детерминизм обязателен: чанк может + прийти через месяц после соседнего). +- Сгенерированный чанк **не пишется на диск**: террейн восстанавливается генератором. + На диск уходит только то, во что построили. + +### 3.4 Что взято из Paper/Bukkit (как образец) + +| у Paper | зачем нам | у нас | +|---|---|---| +| `BlockBreakEvent` (cancellable, `setDropItems`) | сервер решает, ломается ли блок и что падает | `BreakEvent`: `cancelled`, `drops` | +| `BlockPlaceEvent`, `PlayerInteractEvent` | кто что нажал | `InteractEvent` (левая/правая), `PlaceEvent` | +| `ItemMeta` + `PersistentDataContainer` | свои данные на предмете | `ItemStack` + `ItemData` (ключ→значение) | +| `PlayerInventory` / `InventoryClickEvent` | инвентарь, хотбар, защита от дюпа | свой `Inventory` + проверки на сервере | +| `Permissible` / роли | «мир только для админов» | роли сервера, тег `admin` у блоков | +| `ShapedRecipe` / `ShapelessRecipe` | рецепты | свой реестр **с гейтом по чертежу и верстаку** (в Paper такого нет) | + +Чего у Paper нет, а нужно нам: гейт крафта по изученности, прочность/урон/сбор по +классам ресурсов, **структуры вместо блоков мира**. + +--- + +## 4. План работ + +Каждый шаг — законченный кусок, который можно проверить. Порядок важен. + +### Шаг A. Фундамент предметов и инвентаря (следующий) + +- [ ] `ItemType`: id, имя, класс инструмента, класс ресурса, прочность, урон по частям тела, + скорость сбора, `bench`, рецепт. +- [ ] `ItemStack`: тип + количество + прочность + `ItemData` (свой ключ→значение). +- [ ] `Inventory`: слоты, хотбар, что в руках. **Сервер — источник истины.** +- [ ] Реестр предметов + протокол `Inventory` / `InventorySlot`. +- [ ] Клиент: свой реестр + свои текстуры + свой рендер предмета в руке и в слоте + (наши предметы не ванильные `IItem`). +- [ ] **Текстуры предметов — временные** (взяты из ремейка как заглушки). + **ПОМЕТКА: заменить на свои.** +- [ ] Стартовый набор: **камень** (как в Rust — выдаётся первым). + +Критерий готовности: игрок заходит, получает камень в руку, видит его в хотбаре и в руке; +сервер знает, что у него в руках. + +### Шаг B. Ломание и установка — решает сервер + +- [ ] Протокол: `Dig` (START/STOP, позиция, грань) **вместо** «клиент присылает результат»; + `BreakProgress` (0..9) — трещины у всех. +- [ ] Сервер: состояние ломания по образцу `PlayerInteractionManager` + (`PlayerInteractionManager.java:79 updateBlockRemoving`, `:124 onBlockClicked`, + `:216 tryHarvestBlock`): прогресс по твёрдости блока и скорости инструмента, + рассылка прогресса, досягаемость, роль/тег `admin`. +- [ ] Правило из ваниллы: **меч в креативе блок не ломает** + (`PlayerInteractionManager.java:217`). +- [ ] **Клиент ничего не решает:** 4 патча (`Minecraft.clickMouse` → свой `Dig`, + `Minecraft.sendClickBlockToController` → состояние кнопки, + `PlayerControllerMP.clickBlock` → клиент не ломает сам, + `EntityRenderer.isDrawBlockOutline` → контур только там, где можно). + +Критерий готовности: зажатая кнопка ломает **один** блок; блок с тегом `admin` обычному +игроку не ломается ни в выживании, ни в креативе; у остальных — ломается инструментом +того класса, который нужен. + +### Шаг C. Структуры, узлы, постройка + +- [ ] `StructureTemplate` (блоки + AABB + меш + HP + дроп), `StructureInstance`, + `StructureWorld`. Деревья/камни/руда — **узлы**, не блоки мира. +- [ ] Сбор: попадание инструментом → урон по классу ресурса → разрушение → дроп. +- [ ] Постройка: игрок ставит **наши** кастомные предметы-конструкции (не блоки мира). + Снаппинг — см. п. 1.5. +- [ ] Растительность и руда в генерации — через шаблоны структур. + +### Шаг D. Мир один раз, конфиг, барьер + +- [ ] Конфиг: `world.size` (сторона карты в блоках), `world.gamemode`, `world.seed`, + `world.generate`, `barrier.distance`. +- [ ] Мир генерится один раз и отдаётся; изменения игроков — отдельным слоем. +- [ ] Барьер: сервер не пускает; клиент рисует (прозрачность → 0.5 у границы, + блендинг с блоком под игроком в ±5 блоках, дальше размытие в невидимую стену). + +### Шаг E. Транспорт на NIO (независим, можно раньше) + +- [ ] `Selector` + неблокирующие `SocketChannel`, `ClientSession` → конечный автомат, + блокирующие места (HTTP к лаунчеру) — в пул потоков. +- [ ] Проверка: 49 существующих тестов идут по сокету и должны пройти без правок; + + 100 одновременных соединений. + +### Шаг F. DistantView + +- [ ] Сервер шлёт LOD (высоты + цвет) по регионам; клиент кэширует **архивом** и + досылает недостающее. +- [ ] Рендер: квадродерево, **Hi-Z отсечение** (пирамида глубины), `uCamOffset` + (float не хватает на ±2000), зажим UV по мипам, свой шейдер GLSL 330. + +--- + +## 5. Открытые вопросы + +1. **Роли приходят из лаунчера или живут на сервере?** Лаунчер знает роли + (`ROLE_USER … ROLE_CREATOR`), но сервер может держать свои. +2. **Эксперимент на верстаке делаем?** (случайный чертёж за скрап) — в Rust есть. +3. **Урон по частям тела** (голова/грудь/руки/ноги) — сразу или один общий урон? + +--- + +## 6. Что дописать + +- [ ] Полные таблицы предмет→требуемый верстак и предмет→скрап (из вики). +- [ ] Точная таблица сбора по классам ресурсов (дерево/руда/животное/лоза/камень/металл). +- [ ] Список строительных объектов и их сокеты (что куда снаппится) — по п. 1.5.