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 62 additions and 14 deletions
Showing only changes of commit 734521df72 - Show all commits

View File

@ -175,23 +175,37 @@ export class LuaSharedSandbox {
}
const wrapped = `
do
local script = {
-- Если parentExpr вернул primitive у него уже есть :FindFirstChild и пр.
-- Если ничего не вернёт workspace (всегда валидный).
-- script.Parent.Parent (Tool.Parent = StarterPack / Backpack / workspace).
local _scriptParent = ${parentExpr}
if _scriptParent == nil then _scriptParent = workspace end
if _scriptParent.Parent == nil then _scriptParent.Parent = workspace end
local script = setmetatable({
Name = ${JSON.stringify(scriptName)},
Parent = ${parentExpr},
Parent = _scriptParent,
ClassName = "Script",
Disabled = false,
Source = nil,
}
}, {
-- Любой доступ к несуществующему полю workspace
-- (на случай script.Foo:Bar() в старом коде)
__index = function(t, k)
if k == "FindFirstChild" or k == "WaitForChild" or k == "GetChildren" then
return function() return nil end
end
return workspace[k]
end,
})
local co = coroutine.create(function()
-- WATCHDOG: каждые 50000 инструкций yield 1 кадр.
-- Защищает от tight-loop типа:
-- while not parent:FindFirstChild(name) do
-- parent.ChildAdded:wait()
-- end
-- где наш stub :wait() возвращает сразу.
-- WATCHDOG: каждые 100000 инструкций yield 1 кадр.
-- Защищает от tight-loop. yield обёрнут в pcall так как
-- внутри C-call boundary yield бросает ошибку но в этом
-- случае tight-loop наш hook просто будет вызываться позже
-- (когда Lua вернётся из C-call) и yield сработает.
debug.sethook(function()
coroutine.yield(0.016)
end, "", 50000)
pcall(coroutine.yield, 0.016)
end, "", 100000)
-- pcall защищает от runtime-ошибок которые иначе крашат
-- coroutine и могут повредить WASM-стейт. Возвраты
-- handler'а намеренно поглощаются.

View File

@ -1247,6 +1247,15 @@ export function registerRobloxShim(lua, opts) {
inst.FireServer = function (...a) { this.OnServerEvent.Fire(localPlayer, ...a); };
inst.FireClient = function (_p, ...a) { this.OnClientEvent.Fire(...a); };
inst.FireAllClients = function (...a) { this.OnClientEvent.Fire(...a); };
} else if (className === 'SpecialMesh' || className === 'BlockMesh'
|| className === 'CylinderMesh' || className === 'FileMesh') {
inst = newInstance(className, className);
inst.MeshType = { Name: 'Brick', Value: 0 };
inst.MeshId = '';
inst.TextureId = '';
inst.Scale = new RbxVector3(1, 1, 1);
inst.Offset = new RbxVector3(0, 0, 0);
inst.VertexColor = new RbxVector3(1, 1, 1);
} else if (className === 'BindableEvent') {
inst = newInstance('BindableEvent', 'BindableEvent');
inst.Event = makeSignal();
@ -1588,6 +1597,29 @@ export function registerRobloxShim(lua, opts) {
end
wait = rbx_wait
-- Roblox legacy globals
tick = function() return os.time() end -- секунды с epoch
time = function() return os.clock() * 1000 end -- ms аптайм
delay = function(sec, fn) -- delay(sec, fn) задержка + вызов
if type(fn) ~= 'function' then return end
local co = coroutine.create(function()
rbx_wait(sec or 0)
pcall(fn)
end)
coroutine.resume(co)
end
spawn = function(fn) -- spawn(fn) запуск в отдельной coroutine
if type(fn) ~= 'function' then return end
local co = coroutine.create(function() pcall(fn) end)
coroutine.resume(co)
end
-- LoadLibrary("RbxStamper"/"RbxUtility") старый Roblox 2009.
-- Возвращаем пустую таблицу-стаб чтобы скрипт не упал.
LoadLibrary = function(name)
return setmetatable({}, { __index = function() return function() end end })
end
require = require or function(_) return {} end
function __rbxl_resume_co(co)
if not co or coroutine.status(co) ~= 'suspended' then return nil end
local ok, ret = coroutine.resume(co)
@ -1609,10 +1641,12 @@ export function registerRobloxShim(lua, opts) {
-- что приводит к wasmoon promise-detection crash). pcall возвращает
-- (ok, ret1, ret2, ...) мы их не используем.
local co = coroutine.create(function()
-- Тот же watchdog что и в _startSingleScript
-- Тот же watchdog что и в _startSingleScript.
-- yield обёрнут в pcall: внутри C-call boundary yield бросает
-- ошибку, но hook будет вызван позже когда Lua вернётся.
debug.sethook(function()
coroutine.yield(0.016)
end, "", 50000)
pcall(coroutine.yield, 0.016)
end, "", 100000)
pcall(fn, a1, a2, a3, a4)
end)
__rbxl_register_coroutine(handlerId, co)