Files

124 lines
6.9 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// dbg19:修复后全流程真人验证
// 1. D1 与圆圆对话取面包 → 送大宝/咪咪/龟爷爷 → T1 完成(不经隐形柜台)
// 2. D2 与咪咪对话清点货架 → T5 完成(不经隐形货架区)
// 3. 睡觉竞态:低幸福+计时逼近阈值时睡觉 → 不卡死,D2 可正常交互
// 4. 庆典未被误抑制:低幸福计时到点不睡觉 → 庆典正常触发
// 5. T13 彩带 ×4 新坐标可触发
import puppeteer from 'puppeteer-core';
import { spawn } from 'node:child_process';
import net from 'node:net';
const preview = spawn('npx', ['vite','preview','--host','127.0.0.1','--port','4815','--strictPort'], { stdio:'ignore' });
process.on('exit', () => { try{preview.kill()}catch{} });
for (let i=0;i<50;i++){ const ok = await new Promise(r=>{const s=net.connect(4815,'127.0.0.1');s.once('connect',()=>{s.end();r(true)});s.once('error',()=>r(false))}); if(ok)break; await new Promise(r=>setTimeout(r,300)); }
const browser = await puppeteer.launch({ executablePath: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', headless: true, args: ['--autoplay-policy=no-user-gesture-required','--mute-audio'] });
const page = await browser.newPage();
await page.setViewport({ width: 960, height: 560 });
page.on('pageerror', e => console.log('[pageerror]', (e.stack||e.message).slice(0,400)));
page.on('console', m => { if (m.type()==='error') console.log('[console.error]', m.text().slice(0,200)); });
await page.goto('http://127.0.0.1:4815/', { waitUntil: 'networkidle2' });
await page.waitForFunction('window.__game && window.__director', { timeout: 20000 });
await page.waitForFunction(() => window.__game.scene.isActive('TitleScene'), { timeout: 20000 });
await page.evaluate(() => { document.querySelector('#game input[type="text"]').closest('div').querySelector('button').click(); });
await page.waitForFunction(() => window.__game.scene.isActive('HouseScene'), { timeout: 15000 });
const sleep = (ms) => new Promise(r=>setTimeout(r,ms));
const tap = async (code, hold=90) => { await page.keyboard.down(code); await sleep(hold); await page.keyboard.up(code); await sleep(30); };
const ev = (fn, ...a) => page.evaluate(fn, ...a);
const dlgOpen = () => ev(() => { const u = window.__game.scene.getScene('UIScene'); return !!(u && u.payload); });
const dlgText = () => ev(() => { const u = window.__game.scene.getScene('UIScene'); return u && u.dlgBody ? u.dlgBody.text : ''; });
async function drain(maxIter = 40) {
const texts = [];
for (let i = 0; i < maxIter; i++) { if (!(await dlgOpen())) break; texts.push(await dlgText()); await tap('KeyE'); await sleep(160); }
return texts;
}
async function startScene(k) {
await ev((k) => { const sm = window.__game.scene;
for (const sc of sm.getScenes(true)) { const key = sc.scene.key; if (key !== 'UIScene' && key !== k) sm.stop(key); }
sm.start(k, { spawn: 'default' }); }, k);
await page.waitForFunction((kk) => window.__game.scene.isActive(kk), { timeout: 9000 }, k);
await sleep(400); await drain();
}
async function setPlayer(k, x, y) {
await ev((k,x,y) => { const s = window.__game.scene.getScene(k); s.player.setPosition(x, y); s.player.setVelocity(0,0); }, k, x, y);
await sleep(120);
}
async function talkNpc(sceneKey, x, y) {
await setPlayer(sceneKey, x + 40, y + 40);
await setPlayer(sceneKey, x, y + 8);
await tap('KeyE');
await sleep(300);
return drain();
}
const dget = (e) => ev(new Function(`return window.__director.${e}`));
const darr = (e) => ev(new Function(`return [...window.__director.${e}]`));
let fails = 0;
const check = (name, ok, extra = '') => { console.log(`${ok ? 'PASS' : 'FAIL'} ${name}${extra ? ' ' + extra : ''}`); if (!ok) fails++; };
await sleep(500);
console.log('\n=== 1. D1 与圆圆对话取面包 → 送三人 ===');
// 小地图居中偏移:bakery/shop ox=40,oy=10house ox=64,oy=26plaza/lake 无偏移
await startScene('BakeryScene');
const t1 = await talkNpc('BakeryScene', 128, 50); // yuanyuan (88,40)+(40,10)
check('对话圆圆拿到面包', await dget("taskProgress['breadTaken']") === 1, JSON.stringify(t1).slice(0, 80));
await startScene('PlazaScene');
await talkNpc('PlazaScene', 56, 136); // dabao
await startScene('ShopScene');
await talkNpc('ShopScene', 80, 98); // mimi(D1:只是送面包对象,非 T5)
await startScene('LakeScene');
await talkNpc('LakeScene', 200, 136); // guiyeye
const done1 = await darr('tasksDone');
check('T1 送面包完成', done1.includes('T1'), done1.join(','));
check('T3 问好完成', done1.includes('T3'), done1.join(','));
console.log('\n=== 2. D2 与咪咪对话清点货架 ===');
await ev(() => window.__director.setDay(2));
await startScene('ShopScene');
await talkNpc('ShopScene', 80, 98); // mimi
const done2 = await darr('tasksDone');
check('T5 清点完成', done2.includes('T5'), done2.join(','));
check('C5 线索获得', (await darr('clues')).includes('C5'));
console.log('\n=== 3. 睡觉竞态:低幸福计时逼近阈值时睡觉 ===');
await ev(() => { const d = window.__director; d.forceIdle(); d.setDay(1); d.setHappiness(20); });
await startScene('HouseScene');
// lowHappyMs=119700:阈值将在 ~300ms 后(即床淡出 400ms 中途)到达,正中竞态窗口
await ev(() => { const d = window.__director; d.setHappiness(20); d.lowHappyMs = 119700; d.dayElapsedMs = 300000; });
await setPlayer('HouseScene', 88, 90); // 床 (24,56)+(64,26)=(88,82),站 y+8
await tap('KeyE');
let reachedD2 = false, stuckCeleb = false;
for (let i = 0; i < 30; i++) {
await sleep(500);
if (await dlgOpen()) await tap('KeyE');
const day = await dget('day');
if (day === 2) { reachedD2 = true; break; }
}
check('睡觉正常过日到 D2(无庆典抢占)', reachedD2);
stuckCeleb = await dget('celebrationActive');
check('D2 celebrationActive=falseE 可用)', !stuckCeleb);
// D2 交互验证:与日历对话
await startScene('HouseScene');
const cal = await talkNpc('HouseScene', 120, 66); // calendar (56,40)+(64,26)
check('D2 交互正常(日历对话)', cal.length > 0, JSON.stringify(cal).slice(0, 60));
console.log('\n=== 4. 庆典未被误抑制 ===');
await ev(() => { const d = window.__director; d.forceIdle(); d.setHappiness(20); d.lowHappyMs = 119900; });
await sleep(800);
check('低幸福计时到点→庆典正常触发', await dget('celebrationActive'));
await ev(() => window.__director.forceIdle());
console.log('\n=== 5. T13 彩带 ×4 新坐标 ===');
await ev(() => window.__director.setDay(6));
await startScene('PlazaScene');
const ribbons = [[184, 120], [296, 120], [184, 216], [296, 216]];
for (const [x, y] of ribbons) {
await setPlayer('PlazaScene', x + 40, y + 40);
await setPlayer('PlazaScene', x, y + 8);
await tap('KeyE');
await sleep(300);
await drain();
}
check('T13 彩带完成', (await darr('tasksDone')).includes('T13'), (await darr('tasksDone')).join(','));
console.log(`\n${fails === 0 ? '全部通过 ✓' : `失败 ${fails} 项 ✗`}`);
await browser.close();
process.exit(fails === 0 ? 0 : 1);