player/ARCHITECTURE.md
МИН 8428cda555 docs: переписал README/ARCHITECTURE/CONTRIBUTING/SECURITY/CHANGELOG на русский
Юзер указал что вся документация opensource-репо должна быть на русском.
Также:
- .env.example комменты на русском
- package.json description на русском
- Описания org и repo в Gitea обновлены через API
2026-05-27 23:13:28 +03:00

146 lines
9.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Архитектура плеера Рублокса
Как 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)). Это нужно чтобы проект мог продавать коммерческие лицензии корпорациям.