player/tests/rbxl-lua-wait.test.js
min f34320db91
All checks were successful
CI / Lint (pull_request) Successful in 54s
CI / Build (pull_request) Successful in 1m33s
CI / Secret scan (pull_request) Successful in 20s
CI / PR size check (pull_request) Successful in 6s
CI / Deploy to S1 + S2 (pull_request) Has been skipped
feat(rbxl-import): Lua-runtime (wasmoon) для Roblox-скриптов
Часть тест-фичи импорта Roblox-карт (см. rublox/studio rbxl-importer/).

Что добавлено:
- wasmoon (Lua 5.4 WASM) как dep.
- RobloxLuaWorker.js — Worker-хост Lua-VM.
- RobloxLuaSandbox.js — main-side обёртка (по аналогии с ScriptSandbox).
- roblox-shim.js — math (Vector3/Color3/CFrame/UDim2),
  Instance прокси (game/workspace/script/GetService/IsA),
  Part свойства (Position/Color/Material/Anchored/CanCollide),
  RBXScriptSignal (Touched/Heartbeat/Stepped/Connect/Wait).
- roblox-scheduler.js — корутины + wait/task.wait/task.delay/task.spawn,
  автоматический fire Heartbeat/Stepped/RenderStepped на tick.
- roblox-tween.js — TweenService с 10 easing-функциями
  (Linear, Quad, Cubic, Quart, Quint, Sine, Bounce, Elastic, Back, Exponential).
- roblox-services.js — Players/LocalPlayer/Character/Humanoid
  (Health, WalkSpeed, JumpPower, TakeDamage, Died, LoadAnimation),
  UserInputService, RemoteEvent (FireServer/FireClient),
  RemoteFunction, DataStoreService, HttpService.
- roblox-physics.js — BodyVelocity/BodyGyro/BodyPosition/BodyForce/
  BodyAngularVelocity/AlignPosition/LinearVelocity.

Интеграция в GameRuntime:
- В start() проверяется script.kind === 'roblox-lua' →
  _startRobloxLuaScript() запускает RobloxLuaSandbox.
- _handleRobloxLuaCommand() мапит IPC команды (partSet/partVel/playerCmd)
  на PrimitiveManager и game.player API.
- _buildRobloxLuaSceneSnap() готовит snap для workspace:GetChildren.

Тесты: **36/36 passed**.
- mvp (9): math, Instance proxy, Part, IsA.
- wait (5): корутины, wait/task.wait/task.delay.
- tween (2): TweenInfo + Linear easing.
- services (8): Humanoid, DataStore, HttpService, RemoteEvent.
- integration (12): KillBrick, WalkSpeed, Tween-door, BodyVelocity конвейер,
  leaderstats, Checkpoint, циклы с wait, task.spawn, Color/Material,
  RemoteEvent client→server, Heartbeat, Vector3.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-07 18:23:32 +03:00

105 lines
2.9 KiB
JavaScript

/**
* rbxl-lua-wait.test.js — тесты wait/task.wait через шедулер.
*/
import { LuaFactory } from 'wasmoon';
import { registerRobloxApi } from '../src/engine/roblox-shim.js';
import { RobloxScheduler } from '../src/engine/roblox-scheduler.js';
const SCENE = { primitives: {} };
async function run(luaSource, ticks = [0.5, 0.5, 0.5, 0.5, 0.5]) {
const factory = new LuaFactory();
const lua = await factory.createEngine();
const sent = [];
const send = (cmd, payload) => sent.push({ cmd, payload });
registerRobloxApi(lua, { getSceneSnap: () => SCENE, targetPrimitiveId: null, send });
const sched = new RobloxScheduler(lua);
sched.install();
await sched.spawnMain(luaSource);
for (const dt of ticks) {
await sched.tick(dt);
}
lua.global.close();
return sent.filter(s => s.cmd === 'log').map(s => s.payload);
}
const TESTS = [
{
name: 'wait(0) — мгновенный',
lua: `
print("before")
wait(0)
print("after")
`,
expect: ['before', 'after'],
},
{
name: 'wait(1) — резюм после tick',
lua: `
print("step1")
wait(1)
print("step2")
`,
ticks: [0.5, 0.5, 0.5], // 1.5 сек суммарно
expect: ['step1', 'step2'],
},
{
name: 'task.wait(0.5)',
lua: `
print("a")
task.wait(0.5)
print("b")
`,
ticks: [0.5, 0.5],
expect: ['a', 'b'],
},
{
name: 'несколько wait подряд',
lua: `
print("p1")
wait(0.5)
print("p2")
wait(0.5)
print("p3")
`,
ticks: [0.5, 0.5, 0.5, 0.5], // 2 сек
expect: ['p1', 'p2', 'p3'],
},
{
name: 'task.delay (не блокирует)',
lua: `
print("immediate")
task.delay(0.3, function() print("delayed") end)
print("after delay-call")
`,
ticks: [0.5],
expect: ['immediate', 'after delay-call', 'delayed'],
},
];
(async () => {
let passed = 0, failed = 0;
for (const t of TESTS) {
try {
const logs = await run(t.lua, t.ticks);
const texts = logs.map(l => l.text);
const ok = JSON.stringify(texts) === JSON.stringify(t.expect);
if (ok) {
console.log(`${t.name}`);
passed++;
} else {
console.log(`${t.name}`);
console.log(` expected: ${JSON.stringify(t.expect)}`);
console.log(` got: ${JSON.stringify(texts)}`);
failed++;
}
} catch (e) {
console.log(`${t.name} — exception: ${e}`);
failed++;
}
}
console.log(`\n${passed} passed, ${failed} failed`);
process.exit(failed > 0 ? 1 : 0);
})();