// 门往返专项:每条通道双向走一遍,确认到达后 1.2 秒内不被弹回(防出生点压住触发区) import { chromium } from "playwright"; import { createServer } from "vite"; const server = await createServer({ server: { port: 5193 } }); await server.listen(); const browser = await chromium.launch(); const page = await browser.newPage({ viewport: { width: 1280, height: 720 } }); const errors = []; page.on("console", m => { if (m.type() === "error") errors.push(m.text()); }); page.on("pageerror", e => errors.push(e.message)); const sleep = ms => page.waitForTimeout(ms); const tp = (x, y) => page.evaluate(([x, y]) => { const sc = window.__game.scene.getScenes(true).find(s => s.player); sc.player.setPosition(x, y); sc.player.body.reset(x, y); }, [x, y]); const cur = () => page.evaluate(() => window.__director.currentScene); const failures = []; // 沿指定方向持续走 ms 毫秒(模拟真实按键走进出口) const walk = async (key, ms) => { await page.keyboard.down(key); await sleep(ms); await page.keyboard.up(key); }; await page.goto("http://localhost:5193/"); await sleep(2500); await page.fill("#name-input", "门测"); await page.press("#name-input", "Enter"); await sleep(1800); // [出发场景, 门口站位, 行走方向, 目标场景] const LEGS = [ ["house", [88, 110], "s", "plaza"], // 小屋 → 广场 ["plaza", [72, 90], "w", "house"], // 广场 → 小屋 ["house", [88, 110], "s", "plaza"], ["plaza", [152, 90], "w", "bakery"], // 广场 → 面包房 ["bakery", [128, 140], "s", "plaza"], ["plaza", [344, 90], "w", "store"], // 广场 → 杂货店 ["store", [128, 140], "s", "plaza"], ["plaza", [424, 90], "w", "clinic"], // 广场 → 诊所 ["clinic", [96, 110], "s", "plaza"], ["plaza", [20, 148], "a", "lake"], // 广场 → 湖畔 ["lake", [360, 120], "d", "plaza"], // 湖畔 → 广场 ["plaza", [462, 148], "d", "field"], // 广场 → 花田 ["field", [24, 104], "a", "plaza"], // 花田 → 广场 ["plaza", [232, 24], "w", "well"], // 广场 → 古井 ["well", [112, 136], "s", "plaza"], // 古井 → 广场 ["plaza", [232, 296], "s", "fogwall"], // 广场 → 雾墙 ["fogwall", [168, 30], "w", "plaza"], // 雾墙 → 广场(用户报告的死循环路径) ]; for (const [from, [x, y], dir, to] of LEGS) { const at = await cur(); if (at !== from) { console.log(`FAIL 前置不在 ${from}(在 ${at})`); failures.push(from + "->" + to); continue; } await tp(x, y); await sleep(250); await walk(dir, 900); let arrived = false; for (let i = 0; i < 20; i++) { await sleep(150); if ((await cur()) === to) { arrived = true; break; } } await sleep(1200); // 到达后必须站得住 const settled = (await cur()) === to; console.log(`${arrived && settled ? "PASS" : "FAIL"} ${from} → ${to}${arrived && !settled ? "(被弹回!)" : ""}`); if (!(arrived && settled)) failures.push(from + "->" + to); } console.log("CONSOLE ERRORS:", errors.length); console.log("FAILURES:", failures.length, failures.join(" | ")); await browser.close(); await server.close(); process.exit(errors.length || failures.length ? 1 : 0);