feat: 50 игр на Lua + импорт Roblox для всех + поддержка Lua в плеере #39
@ -25,10 +25,11 @@ const SCHEDULER = {
|
|||||||
const HEARTBEAT_SIGNAL = makeSignal();
|
const HEARTBEAT_SIGNAL = makeSignal();
|
||||||
const STEPPED_SIGNAL = makeSignal();
|
const STEPPED_SIGNAL = makeSignal();
|
||||||
|
|
||||||
// Глобальный helper для запуска Lua-handler'ов в собственной coroutine.
|
// Очередь handler'ов которые надо запустить на следующем tickScheduler.
|
||||||
// Без этого Roblox-обработчики которые внутри делают wait() падают с
|
// Этим мы выходим из C-boundary — wait() внутри handler'а становится
|
||||||
// "attempt to yield across a C-call boundary".
|
// безопасным yield в собственной coroutine, потому что handler стартует
|
||||||
let _runHandlerInCoroutine = null;
|
// уже из main loop, а не из синхронного JS-callback.
|
||||||
|
const _pendingHandlerQueue = [];
|
||||||
|
|
||||||
function makeSignal() {
|
function makeSignal() {
|
||||||
const sig = {
|
const sig = {
|
||||||
@ -50,17 +51,10 @@ function makeSignal() {
|
|||||||
sig.connect = sig.Connect;
|
sig.connect = sig.Connect;
|
||||||
sig.Fire = function (...args) {
|
sig.Fire = function (...args) {
|
||||||
for (const fn of [...sig.connections]) {
|
for (const fn of [...sig.connections]) {
|
||||||
// Запускаем handler в его собственной coroutine — это позволяет
|
// Кладём в очередь, чтобы handler стартовал не в текущем
|
||||||
// делать wait() внутри без yield-across-C-boundary ошибки.
|
// JS-callback (откуда yield запрещён), а из tickScheduler
|
||||||
if (_runHandlerInCoroutine) {
|
// в своей coroutine. Безопасно для wait() внутри.
|
||||||
try { _runHandlerInCoroutine(fn, args); } catch (e) {
|
_pendingHandlerQueue.push({ fn, args });
|
||||||
console.error('[Signal handler]', e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try { fn(...args); } catch (e) {
|
|
||||||
console.error('[Signal handler]', e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
sig.fire = sig.Fire;
|
sig.fire = sig.Fire;
|
||||||
@ -1402,11 +1396,11 @@ export function registerRobloxShim(lua, opts) {
|
|||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Запуск Lua-handler'а в собственной coroutine.
|
-- Запуск Lua-handler'а из очереди в собственной coroutine.
|
||||||
-- Используется при Fire сигнала из JS — иначе wait() внутри handler'а
|
-- Вызывается из JS tickScheduler — мы УЖЕ вышли из C-callback,
|
||||||
-- падает с 'attempt to yield across a C-call boundary'.
|
-- так что wait() внутри handler'а — yield в свою coroutine.
|
||||||
__rbxl_next_handler_id = 0
|
__rbxl_next_handler_id = 0
|
||||||
function __rbxl_run_in_coroutine(fn, a1, a2, a3, a4)
|
function __rbxl_drain_handler(fn, a1, a2, a3, a4)
|
||||||
__rbxl_next_handler_id = __rbxl_next_handler_id + 1
|
__rbxl_next_handler_id = __rbxl_next_handler_id + 1
|
||||||
local handlerId = "handler_" .. __rbxl_next_handler_id
|
local handlerId = "handler_" .. __rbxl_next_handler_id
|
||||||
local co = coroutine.create(function() fn(a1, a2, a3, a4) end)
|
local co = coroutine.create(function() fn(a1, a2, a3, a4) end)
|
||||||
@ -1422,8 +1416,8 @@ export function registerRobloxShim(lua, opts) {
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
`);
|
`);
|
||||||
// Кешируем ссылку на функцию для использования из makeSignal
|
// Кешируем ссылку на Lua-функцию запуска handler'а
|
||||||
_runHandlerInCoroutine = lua.global.get('__rbxl_run_in_coroutine');
|
const luaDrainHandler = lua.global.get('__rbxl_drain_handler');
|
||||||
// Добавим Lua-side helper для лога
|
// Добавим Lua-side helper для лога
|
||||||
global.set('__log', (level, text) => {
|
global.set('__log', (level, text) => {
|
||||||
send('log', { level: String(level || 'info'), text: String(text || '') });
|
send('log', { level: String(level || 'info'), text: String(text || '') });
|
||||||
@ -1469,7 +1463,20 @@ export function registerRobloxShim(lua, opts) {
|
|||||||
onDataSnapshot() {},
|
onDataSnapshot() {},
|
||||||
|
|
||||||
tickScheduler(_dt) {
|
tickScheduler(_dt) {
|
||||||
// 0. Tweens
|
// 0a. Lua-handlers из очереди (signal.Fire отложил их сюда).
|
||||||
|
// Запускаем каждый в своей coroutine — wait() внутри безопасен.
|
||||||
|
if (_pendingHandlerQueue.length > 0) {
|
||||||
|
const queue = _pendingHandlerQueue.splice(0, _pendingHandlerQueue.length);
|
||||||
|
for (const h of queue) {
|
||||||
|
try {
|
||||||
|
const a = h.args || [];
|
||||||
|
luaDrainHandler(h.fn, a[0], a[1], a[2], a[3]);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[handler-drain]', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 0b. Tweens
|
||||||
_stepTweens(_dt);
|
_stepTweens(_dt);
|
||||||
const now = SCHEDULER.now();
|
const now = SCHEDULER.now();
|
||||||
// 1. task.delay / task.defer
|
// 1. task.delay / task.defer
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user