feat: 50 игр на Lua + импорт Roblox для всех + поддержка Lua в плеере #39
@ -738,11 +738,16 @@ export function registerRobloxShim(lua, opts) {
|
|||||||
// Главное: __rbxl_resume_co определена в Lua и вызывается из JS через
|
// Главное: __rbxl_resume_co определена в Lua и вызывается из JS через
|
||||||
// lua.global.get('__rbxl_resume_co') — это безопаснее чем doStringSync
|
// lua.global.get('__rbxl_resume_co') — это безопаснее чем doStringSync
|
||||||
// потому что не парсит код заново и не создаёт re-entrant проблем.
|
// потому что не парсит код заново и не создаёт re-entrant проблем.
|
||||||
|
// Lua-side helper для логов (используется в task.wait/resume для отладки)
|
||||||
|
global.set('__log', (level, text) => {
|
||||||
|
send('log', { level: String(level || 'info'), text: String(text || '') });
|
||||||
|
});
|
||||||
|
|
||||||
lua.doStringSync(`
|
lua.doStringSync(`
|
||||||
local function rbx_wait(sec)
|
local function rbx_wait(sec)
|
||||||
sec = sec or 0
|
sec = sec or 0
|
||||||
coroutine.yield(sec)
|
local ret = coroutine.yield(sec)
|
||||||
return sec
|
return ret or sec
|
||||||
end
|
end
|
||||||
if type(task) == 'table' then
|
if type(task) == 'table' then
|
||||||
task.wait = rbx_wait
|
task.wait = rbx_wait
|
||||||
@ -751,20 +756,19 @@ export function registerRobloxShim(lua, opts) {
|
|||||||
end
|
end
|
||||||
wait = rbx_wait
|
wait = rbx_wait
|
||||||
|
|
||||||
-- Вызывается из JS-tickScheduler:
|
|
||||||
-- возвращает next-delay (number) если co yield'нулся ещё раз,
|
|
||||||
-- или nil если co завершился / умер.
|
|
||||||
function __rbxl_resume_co(co)
|
function __rbxl_resume_co(co)
|
||||||
if not co or coroutine.status(co) ~= 'suspended' then return nil end
|
if not co or coroutine.status(co) ~= 'suspended' then return nil end
|
||||||
local ok, ret = coroutine.resume(co)
|
local ok, ret = coroutine.resume(co)
|
||||||
if not ok then
|
if not ok then return false, tostring(ret) end
|
||||||
return false, tostring(ret)
|
|
||||||
end
|
|
||||||
if coroutine.status(co) == 'dead' then return nil end
|
if coroutine.status(co) == 'dead' then return nil end
|
||||||
if type(ret) == 'number' then return ret end
|
if type(ret) == 'number' then return ret end
|
||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
`);
|
`);
|
||||||
|
// Добавим Lua-side helper для лога
|
||||||
|
global.set('__log', (level, text) => {
|
||||||
|
send('log', { level: String(level || 'info'), text: String(text || '') });
|
||||||
|
});
|
||||||
// Достаём ссылку на Lua-функцию один раз; вызовы безопасны (не doStringSync)
|
// Достаём ссылку на Lua-функцию один раз; вызовы безопасны (не doStringSync)
|
||||||
const luaResumeCo = lua.global.get('__rbxl_resume_co');
|
const luaResumeCo = lua.global.get('__rbxl_resume_co');
|
||||||
|
|
||||||
@ -822,8 +826,6 @@ export function registerRobloxShim(lua, opts) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 2. Резюм coroutine'ов которые task.wait()
|
// 2. Резюм coroutine'ов которые task.wait()
|
||||||
// Используем lua.global.get-кешированную __rbxl_resume_co функцию —
|
|
||||||
// безопаснее чем doStringSync (не re-entrant в WASM).
|
|
||||||
const dueCoros = [];
|
const dueCoros = [];
|
||||||
for (let i = waitingCoros.length - 1; i >= 0; i--) {
|
for (let i = waitingCoros.length - 1; i >= 0; i--) {
|
||||||
if (waitingCoros[i].wakeAt <= now) {
|
if (waitingCoros[i].wakeAt <= now) {
|
||||||
@ -836,7 +838,6 @@ export function registerRobloxShim(lua, opts) {
|
|||||||
if (!co) continue;
|
if (!co) continue;
|
||||||
try {
|
try {
|
||||||
const result = luaResumeCo(co);
|
const result = luaResumeCo(co);
|
||||||
// result: number (next delay), nil (done), false+errStr (failed)
|
|
||||||
if (result === null || result === undefined) {
|
if (result === null || result === undefined) {
|
||||||
coroutines.delete(entry.coId);
|
coroutines.delete(entry.coId);
|
||||||
} else if (typeof result === 'number') {
|
} else if (typeof result === 'number') {
|
||||||
@ -844,6 +845,8 @@ export function registerRobloxShim(lua, opts) {
|
|||||||
coId: entry.coId,
|
coId: entry.coId,
|
||||||
wakeAt: SCHEDULER.now() + result * 1000,
|
wakeAt: SCHEDULER.now() + result * 1000,
|
||||||
});
|
});
|
||||||
|
} else if (result === false) {
|
||||||
|
coroutines.delete(entry.coId);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
send('log', { level: 'error', text: `[coroutine ${entry.coId}] ${e?.message || e}` });
|
send('log', { level: 'error', text: `[coroutine ${entry.coId}] ${e?.message || e}` });
|
||||||
|
|||||||
@ -141,7 +141,8 @@ export function handleLuaCommand(_scriptId, cmd, payload, runtime) {
|
|||||||
else if (prop === 'anchored') patch.anchored = value;
|
else if (prop === 'anchored') patch.anchored = value;
|
||||||
else if (prop === 'canCollide') patch.canCollide = value;
|
else if (prop === 'canCollide') patch.canCollide = value;
|
||||||
else if (prop === 'opacity') patch.opacity = value;
|
else if (prop === 'opacity') patch.opacity = value;
|
||||||
if (typeof pm.applyPatch === 'function') pm.applyPatch(primId, patch);
|
if (typeof pm.updateInstance === 'function') pm.updateInstance(primId, patch);
|
||||||
|
else if (typeof pm.applyPatch === 'function') pm.applyPatch(primId, patch);
|
||||||
else if (typeof pm.update === 'function') pm.update(primId, patch);
|
else if (typeof pm.update === 'function') pm.update(primId, patch);
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
return;
|
return;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user