- Текстура studs v4: круглые кружки с усиленным объёмом (normal strength 4.0, запечённый блик/тень) + контактная тень от каждого кружка. Фон 0.97 — цвет остаётся сочным. emissive 45% от цвета на примитивах (Roblox-look). - Версионные имена файлов (studs_v4_*) — обход browser-кэша Babylon. - Color-пикер блоков: в палитре при выборе окрашиваемого блока (studs-block) под категориями появляется ряд из 8 лего-цветов + input «свой цвет». BabylonScene.setActiveBlockColor → addBlock(...,color) при постановке. - DEV-хук ?dev=<имя> (localhost): грузит /dev-<имя>.json в редактор для локального теста без БД (на проде неактивен). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Движок студии Рублокс
Это сердце 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/ — legacy воксельный ландшафт (TerrainManager). Кисти, материалы, plant-кисти. Соединён с
BabylonSceneчерезTerrainManager.jsв корне. - voxel/ — новый chunks-based движок (16×16×16 чанки + greedy meshing). См. RUBLOX_VOXEL_ENGINE_PLAN.md. Пока работает параллельно с legacy TerrainManager как shadow-копия для замеров.
- robloxterrain/ — Roblox-style визуальные эффекты для гладкого ландшафта (vertex AO, slope-darken, distance fog).
- types/ — общие type-определения и enum'ы (BlockTypes, PrimitiveTypes).
5. Скрипты пользователей (sandbox)
ScriptSandbox.js + ScriptSandboxWorker.js — самая опасная часть движка. Тут юзеры пишут JS, который запускается в их браузере при игре.
Каждый скрипт запускается в отдельном Worker (изоляция: нет доступа к DOM, window, fetch). Общение со сценой — только через postMessage и проксированное API game.*:
// что доступно скрипту:
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 (приватный, не публикуется в 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.
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 — воксельный ландшафт
- voxel/README.md — новый chunks-движок
- ../README.md — про папку editor/ выше
- docs/TUTORIAL_ADD_BLOCK.md — добавить новый тип блока
- docs/TUTORIAL_DEBUG_BABYLON.md — отладка Babylon-сцены
- docs/TUTORIAL_ADD_SCRIPT_API.md — добавить API в
game.*
Вопросы — в канал #разработка на https://team.rublox.pro.