fix(lua): partSet применяется через PrimitiveManager.updateInstance (был applyPatch/update — их нет); очистка debug-логов

This commit is contained in:
min 2026-06-08 12:00:29 +03:00
parent 0d7224a2b8
commit ecc2055b3d
2 changed files with 16 additions and 12 deletions

View File

@ -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}` });

View File

@ -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;