# 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.