# Движок студии Рублокс

Это сердце [studio.rublox.pro](https://studio.rublox.pro). Тут живёт всё: рендер Babylon-сцены, физика, скрипты пользователей, мультиплеер, ландшафт, ассет-менеджмент.

Для контрибьютора, который впервые видит этот код — читай этот README сверху вниз, дальше доки по подпапкам.

## 1. Слои движка

Снизу вверх:

```
┌─────────────────────────────────────────────────────┐
│  React UI (panels, тулбары)                         │
├─────────────────────────────────────────────────────┤
│  GameRuntime              ← оркестратор «игрового   │
│  PlayerController           режима» (когда игрок    │
│  ScriptSandbox(Worker)      жмёт Play в редакторе)  │
├─────────────────────────────────────────────────────┤
│  Менеджеры объектов сцены                           │
│    BlockManager     — блоки 1×1×1                   │
│    PrimitiveManager — сферы/цилиндры/конусы         │
│    ModelManager     — GLB-модели из библиотеки      │
│    UserModelManager — модели юзера (CAD-редактор)   │
│    NpcManager       — NPC и враги                   │
│    DecoManager      — трава/цветы/деревья           │
├─────────────────────────────────────────────────────┤
│  Системы поверх сцены                               │
│    PhysicsWorld     — AABB + интеграция Хейуна      │
│    SelectionManager — клик → подсветка              │
│    GizmoController  — translate/rotate/scale gizmos │
│    HistoryManager   — Ctrl+Z / Ctrl+Y               │
│    MultiplayerSync  — Colyseus state-sync           │
├─────────────────────────────────────────────────────┤
│  Низ: BabylonScene = Engine + Scene + Camera        │
│        TerrainManager + voxel/                      │
└─────────────────────────────────────────────────────┘
```

`BabylonScene.js` — точка входа. Создаёт `Engine`, `Scene`, `UniversalCamera` с Roblox-style контролами (ПКМ + WASD-полёт), подключает всех менеджеров.

## 2. Как игрок ставит блок (полный путь)

Это самый частый кейс. Понимаешь его → понимаешь как работают все остальные менеджеры.

```
1. User жмёт ЛКМ в редакторе
   ↓
2. BabylonScene.onCanvasPointerDown
   - делает ray из камеры через курсор
   - scene.pickWithRay()  → выясняет, в какую грань какого меша попали
   ↓
3. Если активен инструмент «Кисть блоков»:
   BlockManager.placeBlock(pos, blockType)
   - вычисляет grid-aligned позицию (округление к 1×1×1)
   - создаёт InstancedMesh от шаблонного меша блока (один draw call на тип)
   - регистрирует в внутренней карте: pos.x|y|z → mesh
   - HistoryManager.push({ action: 'place', pos, type })
   ↓
4. Если активен Multiplayer:
   MultiplayerSync.sendBlockPlaced({ pos, type })
   - летит в Colyseus-комнату
   - сервер броадкастит остальным игрокам
   - у них BlockManager.placeBlock() вызывается снова, но без HistoryManager.push
```

## 3. Менеджеры — зачем их столько

Каждый менеджер владеет одной категорией объектов. Менеджеры **не знают друг о друге** — все общаются через `BabylonScene` (он же `scene`-объект, проброшен в каждый менеджер при init).

| Менеджер | Что хранит | Ключевой метод |
|---|---|---|
| **BlockManager** | блоки grid-aligned | `placeBlock(pos, type)` / `removeBlock(pos)` |
| **PrimitiveManager** | сферы/цилиндры/конусы любого размера | `addPrimitive({ type, pos, size, color })` |
| **ModelManager** | GLB-модели (мечи, деревья, машины) | `addModel({ modelId, pos, rotation, scaling })` |
| **UserModelManager** | модели созданные юзером в встроенном CAD | `addUserModel({ userModelId, pos })` |
| **NpcManager** | NPC и враги (zombies — отдельный `ZombieManager`) | `spawnNpc({ type, pos })` |
| **DecoManager** | мелкие воксельные декорации (трава 0.05м) | `paintDeco(pos, brushSize, model)` |
| **TerrainManager** | гладкий ландшафт (legacy, voxel-режим) | `paintVoxel(pos, material)` |
| **VoxelWorld** + **VoxelRenderer** | новый chunks-based воксельный движок | `setVoxel(x,y,z, type)` |
| **FolderManager** | дерево объектов (как Workspace в Roblox) | `createFolder(name, parentId)` |
| **GuiManager** | UI игры (HUD, меню) | `setUiElement(id, props)` |
| **InventoryManager** | инвентарь игрока (хотбар, рюкзак) | `addItem(itemId, count)` |
| **WeaponSystem** | оружие, выстрелы, перезарядка | `equip(weaponId)` / `fire()` |
| **ScriptSandbox** | JS-скрипты пользователей (см. §5) | `runScript(scriptCode, gameApi)` |

## 4. Подпапки

- **[terrain/](./terrain/)** — legacy воксельный ландшафт (TerrainManager). Кисти, материалы, plant-кисти. Соединён с `BabylonScene` через `TerrainManager.js` в корне.
- **[voxel/](./voxel/)** — новый chunks-based движок (16×16×16 чанки + greedy meshing). См. [RUBLOX_VOXEL_ENGINE_PLAN.md](../../../../RUBLOX_VOXEL_ENGINE_PLAN.md). Пока работает параллельно с legacy TerrainManager как shadow-копия для замеров.
- **[robloxterrain/](./robloxterrain/)** — Roblox-style визуальные эффекты для гладкого ландшафта (vertex AO, slope-darken, distance fog).
- **[types/](./types/)** — общие type-определения и enum'ы (BlockTypes, PrimitiveTypes).

## 5. Скрипты пользователей (sandbox)

`ScriptSandbox.js` + `ScriptSandboxWorker.js` — самая опасная часть движка. Тут юзеры пишут JS, который запускается в их браузере при игре.

Каждый скрипт запускается **в отдельном Worker** (изоляция: нет доступа к DOM, window, fetch). Общение со сценой — только через `postMessage` и проксированное API `game.*`:

```js
// что доступно скрипту:
game.player.damage(10)
game.player.kill()
game.scene.spawn('zombie', { x: 0, y: 0, z: 5 })
game.ui.set('score', 42)
game.broadcast('event', payload)  // другим скриптам
game.onMessage(handler)
game.onTick(handler)              // ~60 раз/сек
```

Полный список API: [reference_kubikon_scripting_api.md](../../../../disaster-recovery/) (приватный, не публикуется в opensource).

**Не звать `game.ui.set` в `onTick` без throttle!** React setState на 60Hz убивает FPS. Дросселировать через 250мс. [feedback_kubikon_ui_set_throttle].

## 6. Что НЕ трогать (опасные оптимизации)

После пары инцидентов задокументировано:

- **`scene.blockMaterialDirtyMechanism = true`** — ломает рендер новых мешей (трейсеры пуль, debris). Babylon не пересчитывает uniforms для новых материалов.
- **`scene.createOrUpdateSelectionOctree()`** в hot path — O(N²) каждый кадр, лагает на 1000+ мешей.
- **`scene.render()` вручную** — Babylon сам в RequestAnimationFrame, дублирование = double render.
- **`setInterval(..., 16)`** для игровой логики — используй `scene.onBeforeRenderObservable.add(fn)`, тогда привязано к рендер-циклу.

Подробнее в [docs/TUTORIAL_DEBUG_BABYLON.md](../../../docs/TUTORIAL_DEBUG_BABYLON.md).

## 7. Game Runtime — особый режим

`GameRuntime.js` — когда юзер жмёт «Play» в редакторе. Это не отдельный код-путь, а **набор флагов** на тех же менеджерах:

- `PlayerController.spawn()` — создаёт игрового персонажа (R15-скелет) на spawn-блоке
- `PhysicsWorld.enable()` — включается AABB-симуляция (в редакторе отключена)
- `ScriptSandbox.startAll()` — запускает все скрипты пользователей
- `MultiplayerSync.join()` — если игра опубликована, коннектится к Colyseus-комнате

Когда юзер жмёт «Stop» — всё откатывается, состояние из HistoryManager восстанавливается.

## 8. Производительность — ориентиры

| Объект | Сколько ок | Сколько начинает лагать |
|---|---|---|
| Блоки (InstancedMesh) | 50 000 | 200 000+ |
| Примитивы (StandardMesh) | 500 | 2000+ |
| GLB-модели | 200 | 500+ (зависит от вершин) |
| NPC | 50 | 100+ (физика дорогая) |
| Активных скриптов | 30 | 100+ (каждый = Worker = поток) |
| Частицы | 5000 | 20 000+ |

FPS-цель: **60 FPS на средних ноутбуках 2020+**, **30 FPS на школьных машинках 2015+**.

## 9. Что почитать дальше

- [terrain/README.md](./terrain/README.md) — воксельный ландшафт
- [voxel/README.md](./voxel/README.md) — новый chunks-движок
- [../README.md](../README.md) — про папку editor/ выше
- [docs/TUTORIAL_ADD_BLOCK.md](../../../docs/TUTORIAL_ADD_BLOCK.md) — добавить новый тип блока
- [docs/TUTORIAL_DEBUG_BABYLON.md](../../../docs/TUTORIAL_DEBUG_BABYLON.md) — отладка Babylon-сцены
- [docs/TUTORIAL_ADD_SCRIPT_API.md](../../../docs/TUTORIAL_ADD_SCRIPT_API.md) — добавить API в `game.*`

Вопросы — в канал `#разработка` на https://team.rublox.pro.
