feat: 50 игр на Lua + импорт Roblox для всех + поддержка Lua в плеере #39

Merged
min merged 215 commits from feat/lua-50-games-bundle into main 2026-06-09 21:59:25 +00:00
3 changed files with 25 additions and 1 deletions
Showing only changes of commit 3271e53acf - Show all commits

View File

@ -62,6 +62,11 @@ ContextActionResult, UserInputState, BorderMode, FormFactor.
аргумента раньше делал tight loop без yield → WASM stack overflow
("memory access out of bounds").
- **Уважаем `enabled: false`** в Roblox-метадате. Roblox-скрипты с
`Disabled = true` — это шаблоны для клонирования (`script.Clean:Clone()`),
не должны запускаться при старте. `parseRobloxLuaMeta()` парсит JSON
из второй строки packed-кода, при `enabled=false` скрипт идёт в `rbxlSkipped`.
### Надо ли портировать в JS-движок?
**Да, всё** — это базовый Roblox-совместимый API, который должен работать

View File

@ -19,7 +19,7 @@ import { ScriptSandbox } from './ScriptSandbox';
import { STORYS_addres } from '../../api/API';
import { PhysicsWorld } from './PhysicsWorld';
import { LabelManager } from './LabelManager';
import { handleLuaCommand, unpackRobloxLuaCode } from './rbxl-lua-integration.js';
import { handleLuaCommand, unpackRobloxLuaCode, parseRobloxLuaMeta } from './rbxl-lua-integration.js';
import { LuaSharedSandbox } from './lua/LuaSharedSandbox.js';
export class GameRuntime {
@ -128,6 +128,11 @@ export class GameRuntime {
for (const s of scripts) {
if (s && typeof s.code === 'string' && s.code.startsWith('// @roblox-lua')) {
if (!runImportedRbxl) { rbxlSkipped++; continue; }
// Уважаем поле enabled=false из Roblox-метадаты: такие скрипты
// были disabled-шаблоны (для клонирования через :Clone()), их
// запуск немедленно крашит coroutine (WASM access out of bounds).
const meta = parseRobloxLuaMeta(s.code);
if (meta && meta.enabled === false) { rbxlSkipped++; continue; }
const luaSource = unpackRobloxLuaCode(s.code);
if (luaSource && luaSource.trim()) {
luaUserBatch.push({

View File

@ -20,6 +20,20 @@ export function unpackRobloxLuaCode(code) {
return code.slice(start, closeIdx);
}
/** Парсит JSON-метадату из 2-й строки packed-кода (`// {"roblox_class":..., "enabled": true}`). */
export function parseRobloxLuaMeta(code) {
if (typeof code !== 'string') return null;
const lines = code.split('\n');
if (lines.length < 2) return null;
const metaLine = lines[1];
if (!metaLine.startsWith('// ')) return null;
try {
return JSON.parse(metaLine.slice(3));
} catch (_) {
return null;
}
}
/** Сцена → snap для shim'а (workspace:GetChildren). */
export function buildLuaSceneSnap(primitives) {
const out = { primitives: {} };