# Архитектура плеера Рублокса

Как 3D-игра загружается, рендерится и синхронизируется. Чтение ~5 минут.

## Общий поток

```
URL = /<gameId>           например /265
   │
   ▼
PlayerAuthProvider          проверяет JWT в localStorage["player_jwt"]
   │                        ИЛИ обменивает URL #ticket=... на JWT
   ▼
useAuth().isAuthenticated
   │
   ▼
KubikonPlayer.jsx           главный контейнер, читает {projectId} из useParams
   │
   ├── GET /api-storys/kubikon3d/projects/{id}    → project_data (JSON)
   │
   ▼
BabylonScene.create()       создание движка Babylon, сцены, света, неба
   │
   ▼
GameRuntime.loadProject()   парсинг project_data, инстанциация всего:
   │                        - BlockManager.placeBlock() × N (Minecraft-блоки)
   │                        - ModelManager.spawnModel() × N (Kenney GLB)
   │                        - DecoManager.placeDeco() × N (декор ландшафта)
   │                        - PrimitiveManager.add() × N (кубы/сферы/цилиндры)
   │                        - PlayerController.spawn() (R15-персонаж + камера)
   │
   ▼
ScriptSandboxWorker         пользовательские JS-скрипты в Web Worker-песочнице.
   │                        Доступный API: game.player, scene, ui, broadcast.
   │
   ▼
MultiplayerSync             опционально. Колyseus-комната, синк позиций.
   │
   ▼
ЦИКЛ РЕНДЕРА (60 fps)       scene.render() каждый кадр
```

## Ключевые модули

### `engine/BabylonScene.js`

Обёртка над `Engine` + `Scene` из Babylon. Создаёт освещение (HemisphericLight + DirectionalLight + теневой генератор), скайбокс, туман. Единый источник правды для ссылки на `scene`.

### `engine/GameRuntime.js`

Оркестратор. Читает `project_data` (JSON, сохранённый редактором студии) и направляет каждый элемент в соответствующий менеджер. Lifecycle-хуки: `loadProject()`, `start()`, `pause()`, `dispose()`.

Также обрабатывает «external URL» резолвинг (`_resolveExternalUrl`) — скрипты игры могут вызвать `game.openUrl('/kubikon/play/12')`, и URL корректно резолвится в сам плеер или на главный сайт.

### `engine/PlayerController.js`

R15-персонаж (15-костный Mixamo-rig). Камеры от первого и третьего лица. Управление WASD/тач. Прыжки, гравитация, столкновения с воксельным гридом + AABB-моделями. Спавн/респавн.

Спец-режимы для GD: `setAutoRun(true)`, `setShipMode(true)` — используются гейммодами Geometry Dash (куб/корабль/волна/НЛО/мяч/паук).

### `engine/BlockManager.js` / `TerrainVoxelBuilder.js`

Воксельный ландшафт. Блоки — uint16 type-id'ы в чанковых массивах. `rebuildChunk(chunkId)` делает greedy meshing → один меш на материал на чанк (~40-100× меньше draw call'ов чем наивно).

### `engine/ModelManager.js`

Загрузка `.glb`-моделей Kenney (или загруженных дизайнерами GLB из `/api-storys/assets/rublox-designer/models/...`). Кеширует `AssetContainer` по `modelTypeId`, инстанциирует клоны при каждом спавне.

### `engine/DecoManager.js`

Лёгкие декоративные пропсы (камни, растения, знаки). Использует `ThinInstanceCount` для огромного перфоманса (тысячи инстансов → один draw call на тип).

### `engine/scripts/ScriptSandboxWorker.js`

Пользовательские JS-скрипты выполняются в отдельном Web Worker. Доступная API-поверхность (только чтение):

```js
// В скрипте игрока:
game.onTick((dt) => { ... });
game.onKey('space', () => { player.jump(); });
game.broadcast('event', payload);
game.player.setHealth(100);
scene.findOne('Cube1').rotateY(0.1);
ui.set({ score: 42 });
```

Скрипты **НЕ имеют** доступа к `window`, `document`, `fetch`, `localStorage`, сети. Запускаются изолированно в Worker'е через строгий postMessage-мост.

### `engine/multiplayer/MultiplayerSync.js`

Colyseus 0.16 клиент. Подключается к комнате per `gameId` если мультиплеер включён. Синхронизирует позиции/повороты/анимации игроков на 20 Hz. Сервер по `VITE_REALTIME_WS`.

### `engine/gd/*` (модули Geometry Dash)

30+ классов реализующих GD-стиль 2D-автораннер-гейммоды в 3D-мире:
- `GdCube.js` — обычный прыжок
- `GdShip.js` — гравитация-флип, полёт
- `GdWave.js` — синусоида-дэш
- `GdBall.js` — флип-прыжок мячом
- `GdUfo.js` — мульти-тап прыжки
- `GdSpider.js` — мгновенный телепорт
- + порталы, ускорители, шипы, финишные линии, трейлы, чекпойнт-музыка

Фабрики для каждого (`GdSpikeFactory`, `GdPortalFactory`, `GdMusicFactory`...) живут в `AdminPreview/gd*/`.

## Поток данных (один кадр)

```
1. ВВОД        клавиатура/тач/геймпад → PlayerController.onInput()
2. ФИЗИКА      гравитация + скорость + столкновения с блоками/моделями
3. СКРИПТЫ     onTick(dt) колбэки пользовательских скриптов (в Worker'е, асинхронно)
4. МУЛЬТИПЛЕЕР читаем удалённые позиции, lerp других игроков
5. РЕНДЕР      Babylon scene.render() → WebGL2 draw calls
6. UI          React ре-рендерится только если вызвали game.ui.set() (throttle 250мс)
```

## Чего НЕТ в плеере

- **Редактирование** — это в [Студии](https://git.rublox.pro/rublox/studio).
- **Лента игр / поиск / публикация** — это на главном сайте (`rublox.pro/app`).
- **Авторизация-UI** — игроки приходят с JWT/ticket. Плеер только читает их.
- **Админка / модерация** — вынесены в приватный репозиторий (`disaster-recovery/` для мейнтейнера).

## Узкие места по производительности (что смотреть первым делом если тормозит)

1. **`game.ui.set()` вызывается каждый кадр** — React setState 60Hz убивает FPS. Дросселируй до 250мс с diff-проверкой.
2. **`scene.findOne()` на старте** — `sceneSnapshot` приходит через rAF; ссылка будет null. Перенеси в `onTick` или `setTimeout(0)`.
3. **`blockMaterialDirtyMechanism=true` в Babylon** — НЕ включать. Ломает рендер новых мешей (debris, трейсеры).
4. **`createOrUpdateSelectionOctree()`** — то же. Ломает превью-призраки редактора.
5. **GLB-загрузка через `SceneLoader` вместо `AssetContainer`** — течёт материалами. Используй `AssetContainer` + `instantiateModelsToScene()`.

## С чего начать новую фичу

| Что хочешь добавить | Начни здесь |
|---|---|
| Новый тип блока | `engine/CONST/blockTypes.js` + текстура в `public/kubikon-assets/blocks/` |
| Новое API для скриптов | `engine/scripts/ScriptSandboxAPI.js` (добавь в `apiSurface`) |
| Новый GD-гейммод | Скопируй `engine/gd/GdBall.js`, зарегистрируй в `GdGameModeRegistry.js` |
| Новый HUD-виджет | `editor-shared/GameHud.jsx` |
| Превью-роут для дизайнера | `AdminPreview/` (например `gdSkins/PreviewGdSkins.jsx`) |
| Мультиплеер-событие | Colyseus-схема в `engine/multiplayer/schemas/` + хендлер в `MultiplayerSync.js` |

## Лицензионные заметки для контрибьюторов

Контрибьютя, ты соглашаешься лицензировать свои изменения под AGPL-3.0 И предоставляешь мейнтейнеру неисключительную безотзывную лицензию на сублицензирование (см. [CLA.md](./CLA.md)). Это нужно чтобы проект мог продавать коммерческие лицензии корпорациям.
