diff --git a/RBXL_SOURCES.md b/RBXL_SOURCES.md new file mode 100644 index 0000000..e0e132e --- /dev/null +++ b/RBXL_SOURCES.md @@ -0,0 +1,124 @@ +# Реестр источников .rbxl / .rbxlx для портирования в Рублокс + +Цель: легально добыть Roblox Place-файлы (.rbxl бинарный / .rbxlx XML) по жанрам +для портирования и публикации на Рублоксе. + +**Форматы:** `.rbxlx` (XML — предпочтителен, читаемый, легко парсить геометрию/CFrame) +· `.rbxl` (бинарный, конвертировать) · `.rbxm`/`.rbxmx` (модели, не целые места). + +> ⚠️ **Главное про публикацию:** «uncopylocked» ≠ свободная лицензия. Для ПУБЛИКАЦИИ +> порта на Рублоксе безопасны только: репо с явной **MIT/Apache/MPL/CC0/CC-BY** + +> официальные ассеты Roblox с разрешением. Архивы чужих игр — только для +> обучения/прототипа парсера, НЕ для публикации. Lua-скрипты не портируются +> автоматом — логику переписываешь сам (это и снижает юр.риски). + +--- + +## ИНСТРУМЕНТЫ (распаковка/парсинг) + +| Инструмент | URL | Назначение | Лицензия | +|---|---|---|---| +| Rojo | https://github.com/rojo-rbx/rojo | place ↔ файлы | MPL-2.0 | +| rbxlx-to-rojo | https://github.com/rojo-rbx/rbxlx-to-rojo | .rbxl/.rbxlx → проект | MPL/MIT (проверить) | +| rbxfile (Go) | https://github.com/robloxapi/rbxfile | парсинг rbxl/rbxlx/rbxm | MIT (проверить) | +| remodel | https://github.com/rojo-rbx/remodel | скриптовая обработка | MPL-2.0 | +| RobloxAPI/spec | https://github.com/RobloxAPI/spec/blob/master/formats/rbxl.md | спека бинарного формата | docs | + +--- + +## (А) ОФИЦИАЛЬНЫЕ — самые надёжные + +### A1. Roblox/Old-Open-Source-Levels — классика от самой Roblox Corp ⭐ +- https://github.com/Roblox/Old-Open-Source-Levels +- Каталог: https://github.com/Roblox/Old-Open-Source-Levels/blob/master/catalog.md +- ~30+ мест 2007-2013 (.rbxl). Жанры: Crossroads (арена/PvP), Castle Warfare, + ROBLOX Battle (бой), Sword Fight in the Dark (PvP), Haunted Mansion (хоррор), + Glass Houses, Pinball Wizards, Happy Home in Robloxia (песочница/мини). +- Лицензия: «free to manipulate however you wish» — **проверь файл LICENSE вручную** перед публикацией. + +### A2. Встроенные шаблоны Roblox Studio +- Список: https://create.roblox.com/docs/resources/templates +- В Studio: открыть шаблон → File → Save to File → .rbxlx +- Baseplate, Castle, Suburban, Village, Racing, Classic Obby, Team Deathmatch/Combat, + Capture the Flag, Line Runner, Pirate Island, Modern City и др. +- Серая зона для публикации «как есть» — используй как базу/учёбу, геометрию делай своей. + +### A3. creator-docs (документация Roblox, open) +- https://github.com/Roblox/creator-docs + +### A4. Internet Archive — Crossroads (все версии 2007-2017) +- https://archive.org/details/roblox_crossroads +- https://archive.org/details/classic-crossroads_202408 + +--- + +## (Б) РЕПОЗИТОРИИ С КОДОМ/МЕСТАМИ (URL из поиска) + +### С подтверждённой свободной лицензией (можно публиковать) +| Репо | URL | Лицензия | Жанр | +|---|---|---|---| +| Vigilant | https://github.com/IsoLogicGames/Vigilant | **MIT** ✅ | co-op horde-survival (шутер) | +| crossroads-rojo | https://github.com/Dekkonot/crossroads-rojo | наследует Crossroads | арена | + +### Open-source игры (лицензию проверить у каждого — файл LICENSE) +| Репо | URL | Жанр | +|---|---|---| +| Miner's Haven | https://github.com/berezaa/minershaven | tycoon/симулятор | +| roblox-gym-tycoon | https://github.com/jason-lee88/roblox-gym-tycoon | tycoon | +| Racing-Kit-Roblox | https://github.com/Astrophsica/Racing-Kit-Roblox | гонки | +| RENTED_old_rbx | https://github.com/ReRand/RENTED_old_rbx | хоррор | +| roblox-rpg | https://github.com/mobyrblx/roblox-rpg | RPG/демо | +| RobloxGames (dwmk) | https://github.com/dwmk/RobloxGames | разное | +| recsObby | https://github.com/Nimblz/recsObby | obby | +| WavyRobloxObby | https://github.com/sammy0127/WavyRobloxObby | obby (.rbxlx) | +| Sight-Obby | https://github.com/TeoJJss/Sight-Obby | obby | +| fps (Anninzy) | https://github.com/Anninzy/fps | FPS | +| roblox-game-example | https://github.com/areshaistg/roblox-game-example | демо-каркас | + +### Архивы чужих игр (ТОЛЬКО обучение/прототип, НЕ публикация — смешанные права) +| Репо | URL | +|---|---| +| uncopylocked-game-collection | https://github.com/Kitaske/uncopylocked-game-collection | +| robloxplacearchive | https://github.com/tropicalbananas/robloxplacearchive | +| RobloxRBXLArchive | https://github.com/LuaGunsX/RobloxRBXLArchive | +| Biggest Uncopylocked Library | https://github.com/KH0DIN/Biggest_Uncopylocked_Roblox_Games_Library | +| GitHub topics | https://github.com/topics/rbxlx · /rbxl · /rbxm · /rojo · /uncopylocked | + +--- + +## (В) САЙТЫ ДЛЯ САМОСТОЯТЕЛЬНОГО СКАЧИВАНИЯ + +### Прямое скачивание .rbxl/.rbxlx +- **GitHub code search** (вход обязателен): `extension:rbxlx`, `extension:rbxl`, + `filename:default.project.json` (корень Rojo-проекта рядом с местом) + https://github.com/search?q=extension%3Arbxlx&type=code +- **GitHub Topics:** https://github.com/topics/rbxlx · https://github.com/topics/rojo +- **Internet Archive:** https://archive.org/ — поиск «roblox place», «rbxl», «crossroads» + +### CC0/CC-BY геометрия для воссоздания (юридически чистейший путь, не .rbxl но low-poly близко к Roblox) +- **Kenney** (CC0): https://kenney.nl/assets — Platformer/Nature/Car/Pirate/City/Prototype Kit, Blocky Characters +- **OpenGameArt** (CC0/CC-BY): https://opengameart.org/ — voxel/low-poly паки +- **itch.io** (фильтр assets+CC0): https://itch.io/game-assets/free/tag-low-poly +- **Poly Pizza** (CC0/CC-BY low-poly): https://poly.pizza/ +- **Quaternius** (CC0 low-poly паки): https://quaternius.com/ + +### Сообщества с открытыми играми (часто прямые ссылки + лицензия) +- DevForum «free & open-sourced games»: https://devforum.roblox.com/t/lots-of-free-open-sourced-games/525670 +- DevForum «Open Source Arena FPS»: https://devforum.roblox.com/t/open-source-arena-fps/1034576 +- Uplift Games open source: https://www.uplift.games/open-source + +--- + +## ЮРИДИЧЕСКИЕ ПРАВИЛА (коротко) + +- ✅ Публиковать можно: **MIT / Apache-2.0 / MPL-2.0 / CC0 / CC-BY** (CC-BY — с атрибуцией). +- ❌ Нельзя: **GPL/AGPL** (заразные), **CC-BY-NC** (некоммерч.), **без лицензии** (= all rights reserved), + чужие игры через game-savers/декомпиляторы (нарушение DMCA/ToS). +- ⚠️ «Uncopylocked» = только разрешение копировать в Studio, НЕ передача прав. +- ⚠️ Официальные шаблоны Studio — учиться ОК, публиковать «как есть» — серая зона. + +**Рекомендация для наполнения Рублокса легально:** +1. Геометрия под чистую публикацию → Kenney/OpenGameArt CC0. +2. Классика Roblox-стиля → Roblox/Old-Open-Source-Levels (проверить LICENSE) + Crossroads. +3. Полная игра с кодом → Vigilant (MIT). +4. Масса .rbxl для теста парсера → архивы из (Б) + GitHub topics. diff --git a/src/editor/engine/BabylonScene.js b/src/editor/engine/BabylonScene.js index f54f66c..175c430 100644 --- a/src/editor/engine/BabylonScene.js +++ b/src/editor/engine/BabylonScene.js @@ -3035,13 +3035,6 @@ export class BabylonScene { // Без этого onTouch финиша/плитки не срабатывает (игрок встал). const EPS = 0.25; - // Диагностика раз в секунду через time-based throttle - if (!this._touchDbgT0) this._touchDbgT0 = performance.now(); - const _nowDbg = performance.now(); - if (_nowDbg - this._touchDbgT0 > 1000) { - this._touchDbgT0 = _nowDbg; - console.warn(`[TouchDbg] pos=(${px.toFixed(2)},${py.toFixed(2)},${pz.toFixed(2)}) scripts=${scripts.length}`); - } // 1) Касания объектов с target-скриптами (ключ touchState = 's:'+scriptId) let _firedThisFrame = 0; for (const s of scripts) { @@ -5537,7 +5530,7 @@ export class BabylonScene { }; clip.scripts = (this._scripts || []) .filter(s => matchTarget(s.target)) - .map(s => ({ code: s.code, name: s.name || null })); + .map(s => ({ code: s.code, name: s.name || null, language: s.language || 'js' })); } catch (e) { clip.scripts = []; } try { localStorage.setItem('kubikon_clipboard', JSON.stringify(clip)); } catch (e) { /* ignore — приватный режим / переполнение */ } @@ -7769,6 +7762,7 @@ export class BabylonScene { code: s.code, target: s.target || null, name: s.name || null, + language: s.language === 'lua' ? 'lua' : 'js', })), }, editorCamera: this.camera ? { diff --git a/src/editor/engine/lua/LuaSharedWorker.js b/src/editor/engine/lua/LuaSharedWorker.js index aff4a94..b6ef2fc 100644 --- a/src/editor/engine/lua/LuaSharedWorker.js +++ b/src/editor/engine/lua/LuaSharedWorker.js @@ -21,7 +21,9 @@ * и вызывает Lua-side Fire по соответствующему signal'у */ -let _wasmoon = null; +// Статический импорт — Vite корректно бандлит wasmoon в worker +import { LuaFactory } from 'wasmoon'; +import { registerRobloxShim } from './RobloxShim.js'; // Главное состояние VM (на весь life-cycle Worker'а) const state = { @@ -72,23 +74,21 @@ function logToMain(level, text) { async function handleInit(payload) { state.ipcId = payload?.ipcId || 0; send('boot', { ipcId: state.ipcId }); - // Загрузить wasmoon - _wasmoon = await import(/* @vite-ignore */ 'wasmoon'); - const { LuaFactory } = _wasmoon; - const factory = new LuaFactory(); - state.vm = await factory.createEngine({ openStandardLibs: true }); - - // Регистрируем минимальный Roblox shim - const { registerRobloxShim } = await import('./RobloxShim.js'); - state.api = registerRobloxShim(state.vm, { - send, - getSceneSnapshot: () => state.scenes, - getGuiTree: () => state.guiTree, - scheduleWait: (sec) => scheduleWait(sec), - }); - - state.isReady = true; - send('ready', {}); + try { + const factory = new LuaFactory(); + state.vm = await factory.createEngine({ openStandardLibs: true }); + state.api = registerRobloxShim(state.vm, { + send, + getSceneSnapshot: () => state.scenes, + getGuiTree: () => state.guiTree, + scheduleWait: (sec) => scheduleWait(sec), + }); + state.isReady = true; + send('ready', {}); + } catch (err) { + // Это самое важное — без этого юзер не видит почему ничего не работает + logToMain('error', `[LuaWorker init FATAL] ${err?.message || err}\nstack: ${err?.stack || '?'}`); + } } function handleAddScriptsBatch(payload) { diff --git a/src/editor/engine/lua/RobloxShim.js b/src/editor/engine/lua/RobloxShim.js index 1d449fe..79f7d3d 100644 --- a/src/editor/engine/lua/RobloxShim.js +++ b/src/editor/engine/lua/RobloxShim.js @@ -57,13 +57,21 @@ class RbxVector3 { this.X = +x; this.Y = +y; this.Z = +z; } static new(x, y, z) { return new RbxVector3(x, y, z); } - Magnitude() { return Math.hypot(this.X, this.Y, this.Z); } + // В Roblox Magnitude/Unit это PROPERTY (без скобок), а не методы. + get Magnitude() { return Math.hypot(this.X, this.Y, this.Z); } get magnitude() { return Math.hypot(this.X, this.Y, this.Z); } - Unit() { - const m = this.Magnitude() || 1; + get Unit() { + const m = Math.hypot(this.X, this.Y, this.Z) || 1; + return new RbxVector3(this.X / m, this.Y / m, this.Z / m); + } + get unit() { + const m = Math.hypot(this.X, this.Y, this.Z) || 1; + return new RbxVector3(this.X / m, this.Y / m, this.Z / m); + } + Normalize() { + const m = Math.hypot(this.X, this.Y, this.Z) || 1; return new RbxVector3(this.X / m, this.Y / m, this.Z / m); } - Normalize() { return this.Unit(); } Dot(b) { return this.X * b.X + this.Y * b.Y + this.Z * b.Z; } Cross(b) { return new RbxVector3(