All checks were successful
Тест-фича для МИНа. Полное описание в rbxl-importer/INFO_PROCESS.md. Backend (rbxl-importer/ на VM 130 S1): - Python-парсер Roblox Binary (28+ типов значений) - Asset downloader через Marfusha proxy + .ROBLOSECURITY cookie - Mesh→GLB конвертер (v1-v5) - Converter Roblox-классов → project_data - Flask API: /analyze + /create Frontend: - API.js + components/RbxlImportModal.jsx (drag-n-drop) Тестовый импорт Easy Obby: project_id 2697, 2244 primitives + 742 lua-scripts + 5 ассетов. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
101 lines
8.2 KiB
Markdown
101 lines
8.2 KiB
Markdown
# rbxl-importer: лог разработки
|
||
|
||
## 2026-06-07
|
||
|
||
### Фаза 0. Подготовка (✓)
|
||
|
||
- Освобождено место на S1: удалён `pve/data` LV (+133 GB), VM 111/112/114/116 (+285 GB). Свободно стало 419 GB в VG `pve`.
|
||
- Создана **VM 130 rbxl-importer** (IP 192.168.1.130, Ubuntu 22.04, 4 vCPU, 4 GB RAM, 200 GB).
|
||
- Установлены: Docker, Python 3.11+venv, nginx, postgresql-client.
|
||
- Клонированы **studio-rbxl-import** и **player-rbxl-import** worktree, ветка `feat/rbxl-import`.
|
||
- Smoke-test парсера на `Escape Easy Obby Parkour Uncopylocked.rbxl` (8205 instances, 120 классов).
|
||
|
||
### Фаза 1. Парсер `.rbxl` (✓)
|
||
|
||
- Реализованы файлы: `rbxl_binreader.py`, `rbxl_types.py`, `rbxl_parser.py`.
|
||
- Декодирование 28+ Roblox PROP типов: String, Bool, Int32, Float, Double, UDim, UDim2, Ray, Faces, Axes, BrickColor, Color3, Vector2, Vector3, CFrame, Quaternion, Enum, Referent, Vector3int16, NumberSequence, ColorSequence, NumberRange, Rect, PhysicalProperties, Color3uint8, Int64, SharedString, Bytecode, OptionalCFrame, UniqueId, Font.
|
||
- Особенности формата покрыты: interleaved-transformed массивы, zigzag для signed int, Roblox float encoding, LZ4 chunks.
|
||
- **Протестировано на 6 файлах: 0 warnings**:
|
||
- `easy_obby.rbxl` (Easy Obby Parkour, 437 KB, 8205 instances)
|
||
- `miners-haven.rbxl` (Miners Haven, 8 MB, **60950 instances**)
|
||
- 4 synthetic из `rojo-rbx/rbx-dom/benches/files/`
|
||
|
||
### Фаза 2. Asset pipeline (✓)
|
||
|
||
- БД: миграция `001_roblox_assets.sql` (3 таблицы) применена в `storys_db` (S2 primary через autossh туннель S1 PVE 192.168.1.152:25435).
|
||
- `asset_downloader.py`: дедупликация по `rbx_asset_id` + sha256, retry с backoff, классификация по content-type/magic bytes.
|
||
- `asset_proxy.py`: режимы `disabled` / `direct` / `http_proxy` / `cloudflare_worker`. Используется `http_proxy` через Marfusha xray (85.192.61.244:39237).
|
||
- **Cookie auth**: `.ROBLOSECURITY` от аккаунта `minkorenovsk2` сохранён в `/home/min/.roblosecurity` на VM 130, EnvironmentFile подключен в systemd unit.
|
||
- `mesh_converter.py`: парсер Roblox `.mesh` v1-v5 + GLB writer (glTF 2.0 binary).
|
||
- **v1.00** ASCII протестирован: 500 facets, 1500 vertices → 54900 байт GLB.
|
||
- v2-v5 binary — написаны, проверим на реальных файлах.
|
||
- `nginx` на VM 130: `/opt/roblox-assets/` отдаётся как `https://assets.rublox.pro/roblox/...` с CORS.
|
||
|
||
### Фаза 3. Конвертер геометрии (✓)
|
||
|
||
- `converter.py`: маппинг 30+ Roblox-классов → Rublox `project_data`.
|
||
- `Part`, `WedgePart`, `CornerWedgePart`, `TrussPart` → primitives (cube/wedge/cornerwedge).
|
||
- `MeshPart`, `UnionOperation` → glbModels (с fallback на bbox cube).
|
||
- `SpawnLocation` → scene.spawnPoint.
|
||
- `Lighting` → scene.environment.
|
||
- `Sound` → scene.sounds.
|
||
- `Script`/`LocalScript`/`ModuleScript` → scene.scripts с kind='roblox-lua' и raw lua_source.
|
||
- Material enum (Plastic→glossy, Neon→neon, Metal→metal, Glass→glass, ...).
|
||
- CFrame → position + Euler XYZ (system axes Roblox = Babylon: right-handed Y-up).
|
||
- Scale: 1 Roblox stud = 0.28 м (настраиваемо).
|
||
- **Easy Obby результат**: 2244 primitives + 742 lua-scripts + 5 ассетов (sounds) для скачки.
|
||
|
||
### Фаза 4. Lua-runtime + Roblox API shim (✓)
|
||
|
||
- **wasmoon** (Lua 5.4 WASM) интегрирован в `player/studio` (npm install).
|
||
- `RobloxLuaWorker.js` — Worker-хост с инициализацией wasmoon, IPC с main thread.
|
||
- `RobloxLuaSandbox.js` — main-side обёртка.
|
||
- `roblox-shim.js` — math классы (Vector3, Color3, CFrame, UDim2), Instance прокси (game, workspace, script, GetService, GetChildren, FindFirstChild, IsA с иерархией классов), Part свойства (Position/CFrame/Size/Color/Material/Anchored/CanCollide/Transparency), RBXScriptSignal (Touched, Heartbeat, Stepped, RenderStepped, Connect, Wait, Disconnect).
|
||
- `roblox-scheduler.js` — корутины через `coroutine.create/resume/yield`, шедулер для wait/task.wait/task.delay/task.spawn, автоматический fire Heartbeat/Stepped/RenderStepped на каждом tick.
|
||
- `roblox-tween.js` — TweenService с 10 easing-функциями (Linear, Quad, Cubic, Quart, Quint, Sine, Bounce, Elastic, Back, Exponential) для Vector3/Color3/CFrame/number.
|
||
- `roblox-services.js` — Players, LocalPlayer, Character, Humanoid (Health, WalkSpeed, JumpPower, TakeDamage, Died), UserInputService, RemoteEvent (FireServer/FireClient/OnServerEvent), RemoteFunction, DataStoreService (GetAsync/SetAsync/IncrementAsync), HttpService (JSONEncode/Decode), ContextActionService stub.
|
||
- `roblox-physics.js` — BodyVelocity, BodyGyro, BodyPosition, BodyForce, BodyAngularVelocity, AlignPosition, LinearVelocity.
|
||
|
||
### Тесты Lua-runtime: **36/36 ✓**
|
||
|
||
- `tests/rbxl-lua-mvp.test.js` — math + Instance + Part + IsA (**9/9**)
|
||
- `tests/rbxl-lua-wait.test.js` — корутины + wait/task.wait/task.delay (**5/5**)
|
||
- `tests/rbxl-lua-tween.test.js` — TweenService + Linear easing (**2/2**)
|
||
- `tests/rbxl-lua-services.test.js` — Humanoid + DataStore + HttpService + RemoteEvent (**8/8**)
|
||
- `tests/rbxl-lua-integration.test.js` — реалистичные obby/simulator снейппеты (**12/12**):
|
||
KillBrick, WalkSpeed boost, Tween door, BodyVelocity конвейер, leaderstats, DataStore checkpoint, циклы с wait, task.spawn параллель, Color3 + Material смена, RemoteEvent client→server, Heartbeat счётчик, Vector3 arithmetic.
|
||
|
||
### Фаза 5. Flask API + UI (✓)
|
||
|
||
- `src/app.py` Flask:
|
||
- `GET /health` → ok
|
||
- `POST /import/rbxl/analyze` → парсер + report + preview_hash (Redis 20 мин TTL)
|
||
- `POST /import/rbxl/create` → скачка ассетов + конверт mesh→GLB + INSERT в kubikon3d_projects
|
||
- Запущен через **systemd unit** `rbxl-importer.service` (Restart=on-failure, EnvironmentFile с cookie).
|
||
- Redis (Docker `redis-rbxl`) для preview cache.
|
||
- `studio/src/components/RbxlImportModal.jsx` — React компонент с drag-n-drop, отчётом, формой создания. Доступен только МИНу.
|
||
- `studio/src/api/rbxlImporterApi.js` — клиент.
|
||
- Тест-результат: **Easy Obby импортирован как project_id 2697** (2244 primitives, 742 lua-scripts, 5 ассетов скачано без ошибок).
|
||
|
||
### Фаза 6. Совместимость с плеером + DNS (✓)
|
||
|
||
- `GameRuntime.js`: добавлен `_startRobloxLuaScript()` метод и ветка `if (s.kind === 'roblox-lua')` в `start()`.
|
||
- `_handleRobloxLuaCommand()`: маппит IPC команды от Lua-sandbox (partSet, partVel, playerCmd) на PrimitiveManager и game.player API.
|
||
- `_buildRobloxLuaSceneSnap()`: преобразует projectData.scene.primitives → формат для Lua (workspace:GetChildren).
|
||
- **NPM proxy_host** на S1 NPM (VM 101 192.168.1.43): `assets.rublox.pro` и `api-rbxl.rublox.pro` → VM 130:80.
|
||
- **DNS Cloudflare**: 2 A-записи (proxied=false) → 85.175.7.40 (S1 публичный IP).
|
||
- **End-to-end протестировано**: `https://api-rbxl.rublox.pro/health` → 200 OK.
|
||
|
||
### Фаза 7. Документация (в работе)
|
||
|
||
- README.md в rbxl-importer/
|
||
- INFO_PROCESS.md (этот файл)
|
||
- TODO: commit + PR в Gitea для studio и player worktree.
|
||
|
||
## Известные ограничения
|
||
|
||
- Lua-runtime пока MVP: нет GUI (ScreenGui/Frame/TextLabel), нет `:Wait()` на сигналах через корутины (только `Connect`), нет Animation/KeyframeSequence.
|
||
- CSG meshes (UnionOperation) парсятся, но конверт в GLB не реализован — bbox cube fallback.
|
||
- Terrain voxel grid конвертится в заглушку (плоский ландшафт).
|
||
- TouchEvent в плеере не fire'ится автоматически из физики Babylon — нужно добавить collision broadcaster.
|