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
2 changed files with 38 additions and 4 deletions
Showing only changes of commit 932ef2bc20 - Show all commits

View File

@ -134,6 +134,13 @@ export class GameRuntime {
// запуск немедленно крашит coroutine (WASM access out of bounds). // запуск немедленно крашит coroutine (WASM access out of bounds).
const meta = parseRobloxLuaMeta(s.code); const meta = parseRobloxLuaMeta(s.code);
if (meta && meta.enabled === false) { rbxlSkipped++; continue; } if (meta && meta.enabled === false) { rbxlSkipped++; continue; }
// Пропускаем Regeneration-скрипты: у нас Anchored=True для
// импорта, постройки не разрушаются, регенерация не нужна.
// Их работа (model:remove + Clone) даст визуальные глитчи.
const sname = String(s.name || '').toLowerCase();
if (sname.startsWith('regenerate') || sname === 'regenerationscript') {
rbxlSkipped++; continue;
}
const luaSource = unpackRobloxLuaCode(s.code); const luaSource = unpackRobloxLuaCode(s.code);
if (luaSource && luaSource.trim()) { if (luaSource && luaSource.trim()) {
// Эвристика Tool: если скрипт ссылается на Equipped/Activated // Эвристика Tool: если скрипт ссылается на Equipped/Activated
@ -4258,6 +4265,12 @@ export class GameRuntime {
try { player.walkSpeed = Number(payload.value) || player.walkSpeed; } catch (_) {} try { player.walkSpeed = Number(payload.value) || player.walkSpeed; } catch (_) {}
} else if (payload.prop === 'jumpPower') { } else if (payload.prop === 'jumpPower') {
try { player.jumpPower = Number(payload.value) || player.jumpPower; } catch (_) {} try { player.jumpPower = Number(payload.value) || player.jumpPower; } catch (_) {}
} else if (payload.prop === 'maxHealth') {
try {
const max = Math.max(1, Number(payload.value) || 100);
player.maxHp = max;
if (player.hp > max) player.hp = max;
} catch (_) {}
} }
return; return;
} }

View File

@ -831,10 +831,31 @@ export function registerRobloxShim(lua, opts) {
const humanoid = newInstance('Humanoid', 'Humanoid'); const humanoid = newInstance('Humanoid', 'Humanoid');
humanoid.Parent = character; humanoid.Parent = character;
humanoid.Health = 100; let _hp = 100, _maxHp = 100, _ws = 16, _jp = 50;
humanoid.MaxHealth = 100; Object.defineProperty(humanoid, 'Health', {
humanoid.WalkSpeed = 16; get() { return _hp; },
humanoid.JumpPower = 50; set(v) {
_hp = Math.max(0, Math.min(_maxHp, Number(v) || 0));
try { humanoid.HealthChanged.Fire(_hp); } catch (_) {}
send('playerSet', { prop: 'health', value: _hp });
},
});
Object.defineProperty(humanoid, 'MaxHealth', {
get() { return _maxHp; },
set(v) {
_maxHp = Math.max(1, Number(v) || 100);
if (_hp > _maxHp) humanoid.Health = _maxHp;
send('playerSet', { prop: 'maxHealth', value: _maxHp });
},
});
Object.defineProperty(humanoid, 'WalkSpeed', {
get() { return _ws; },
set(v) { _ws = Number(v) || 16; send('playerSet', { prop: 'walkSpeed', value: _ws }); },
});
Object.defineProperty(humanoid, 'JumpPower', {
get() { return _jp; },
set(v) { _jp = Number(v) || 50; send('playerSet', { prop: 'jumpPower', value: _jp }); },
});
humanoid.Died = makeSignal(); humanoid.Died = makeSignal();
humanoid.HealthChanged = makeSignal(); humanoid.HealthChanged = makeSignal();
humanoid.Touched = makeSignal(); humanoid.Touched = makeSignal();