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

9.3 KiB
Raw Permalink Blame History

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

Как 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-поверхность (только чтение):

// В скрипте игрока:
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мс)

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

  • Редактирование — это в Студии.
  • Лента игр / поиск / публикация — это на главном сайте (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). Это нужно чтобы проект мог продавать коммерческие лицензии корпорациям.