feat(rbxl): XML-������ ������ .rbxl + Day/Night + Tool/Mouse/Backpack flow #38
@ -734,10 +734,11 @@ export function registerRobloxShim(lua, opts) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Лагалейн Lua-код: определяем task.wait, wait, и обёртку для скрипта.
|
// Lua-prelude: task.wait через coroutine.yield + готовая resume-функция.
|
||||||
// Этот код выполняется ВНУТРИ Lua VM.
|
// Главное: __rbxl_resume_co определена в Lua и вызывается из JS через
|
||||||
|
// lua.global.get('__rbxl_resume_co') — это безопаснее чем doStringSync
|
||||||
|
// потому что не парсит код заново и не создаёт re-entrant проблем.
|
||||||
lua.doStringSync(`
|
lua.doStringSync(`
|
||||||
-- task.wait(sec) → coroutine.yield(sec); main-loop вернёт через delay sec
|
|
||||||
local function rbx_wait(sec)
|
local function rbx_wait(sec)
|
||||||
sec = sec or 0
|
sec = sec or 0
|
||||||
coroutine.yield(sec)
|
coroutine.yield(sec)
|
||||||
@ -749,7 +750,23 @@ export function registerRobloxShim(lua, opts) {
|
|||||||
task = { wait = rbx_wait }
|
task = { wait = rbx_wait }
|
||||||
end
|
end
|
||||||
wait = rbx_wait
|
wait = rbx_wait
|
||||||
|
|
||||||
|
-- Вызывается из JS-tickScheduler:
|
||||||
|
-- возвращает next-delay (number) если co yield'нулся ещё раз,
|
||||||
|
-- или nil если co завершился / умер.
|
||||||
|
function __rbxl_resume_co(co)
|
||||||
|
if not co or coroutine.status(co) ~= 'suspended' then return nil end
|
||||||
|
local ok, ret = coroutine.resume(co)
|
||||||
|
if not ok then
|
||||||
|
return false, tostring(ret)
|
||||||
|
end
|
||||||
|
if coroutine.status(co) == 'dead' then return nil end
|
||||||
|
if type(ret) == 'number' then return ret end
|
||||||
|
return 0
|
||||||
|
end
|
||||||
`);
|
`);
|
||||||
|
// Достаём ссылку на Lua-функцию один раз; вызовы безопасны (не doStringSync)
|
||||||
|
const luaResumeCo = lua.global.get('__rbxl_resume_co');
|
||||||
|
|
||||||
// === Setter Part-свойств (Position/Size/Color/...) ===
|
// === Setter Part-свойств (Position/Size/Color/...) ===
|
||||||
// Юзер пишет: part.Position = Vector3.new(0, 10, 0)
|
// Юзер пишет: part.Position = Vector3.new(0, 10, 0)
|
||||||
@ -805,39 +822,32 @@ export function registerRobloxShim(lua, opts) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 2. Резюм coroutine'ов которые task.wait()
|
// 2. Резюм coroutine'ов которые task.wait()
|
||||||
// Скрипт-coroutine при первом запуске yield'ит с delay (от task.wait).
|
// Используем lua.global.get-кешированную __rbxl_resume_co функцию —
|
||||||
// Мы регистрируем delay через __rbxl_schedule_resume? Нет — проще:
|
// безопаснее чем doStringSync (не re-entrant в WASM).
|
||||||
// отслеживаем последний yield-результат через coroutine.resume → возвращает
|
const dueCoros = [];
|
||||||
// delay. После init скрипта проверим всех coroutines: если status==suspended,
|
for (let i = waitingCoros.length - 1; i >= 0; i--) {
|
||||||
// и им пора — резюмируем.
|
if (waitingCoros[i].wakeAt <= now) {
|
||||||
for (const [coId, co] of coroutines) {
|
dueCoros.push(waitingCoros[i]);
|
||||||
let entry = waitingCoros.find(w => w.coId === coId);
|
waitingCoros.splice(i, 1);
|
||||||
if (!entry) {
|
|
||||||
// Первый раз видим этот co — нужно вытащить delay из yield-результата.
|
|
||||||
// Это сделано в _onYield ниже.
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
if (entry.wakeAt > now) continue;
|
}
|
||||||
// Время резюмить
|
for (const entry of dueCoros) {
|
||||||
waitingCoros.splice(waitingCoros.indexOf(entry), 1);
|
const co = coroutines.get(entry.coId);
|
||||||
|
if (!co) continue;
|
||||||
try {
|
try {
|
||||||
const code = `
|
const result = luaResumeCo(co);
|
||||||
local co = __rbxl_get_co(${JSON.stringify(coId)})
|
// result: number (next delay), nil (done), false+errStr (failed)
|
||||||
if co and coroutine.status(co) == 'suspended' then
|
if (result === null || result === undefined) {
|
||||||
local ok, ret = coroutine.resume(co)
|
coroutines.delete(entry.coId);
|
||||||
if not ok then
|
} else if (typeof result === 'number') {
|
||||||
__rbxl_send_error(${JSON.stringify(coId)}, tostring(ret))
|
waitingCoros.push({
|
||||||
__rbxl_unregister_coroutine(${JSON.stringify(coId)})
|
coId: entry.coId,
|
||||||
elseif type(ret) == 'number' then
|
wakeAt: SCHEDULER.now() + result * 1000,
|
||||||
__rbxl_schedule_resume(${JSON.stringify(coId)}, ret)
|
});
|
||||||
elseif coroutine.status(co) == 'dead' then
|
}
|
||||||
__rbxl_unregister_coroutine(${JSON.stringify(coId)})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
`;
|
|
||||||
lua.doStringSync(code);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
send('log', { level: 'error', text: `[coroutine resume ${coId}] ${e?.message || e}` });
|
send('log', { level: 'error', text: `[coroutine ${entry.coId}] ${e?.message || e}` });
|
||||||
|
coroutines.delete(entry.coId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user