132 lines
6.6 KiB
JavaScript
132 lines
6.6 KiB
JavaScript
// dbg16:复现「面包无法提交」与「第一天睡觉卡死」
|
||
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,600)));
|
||
page.on('console', m => { if (m.type()==='error') console.log('[console.error]', m.text().slice(0,300)); });
|
||
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());
|
||
const choosing = await ev(() => { const u = window.__game.scene.getScene('UIScene'); return u.showingChoices; });
|
||
await tap(choosing ? 'Digit1' : 'KeyE');
|
||
await sleep(160);
|
||
}
|
||
return texts;
|
||
}
|
||
async function startScene(k, spawn='default') {
|
||
await ev((k,s) => {
|
||
const sm = window.__game.scene;
|
||
for (const sc of sm.getScenes(true)) { const kk = sc.scene.key; if (kk !== 'UIScene' && kk !== k) sm.stop(kk); }
|
||
sm.start(k, { spawn: s });
|
||
}, k, spawn);
|
||
await page.waitForFunction((kk) => window.__game.scene.isActive(kk), { timeout: 9000 }, k);
|
||
await sleep(500);
|
||
}
|
||
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);
|
||
}
|
||
const dstate = () => ev(() => ({
|
||
day: window.__director.day,
|
||
breadTaken: window.__director.taskProgress['breadTaken'] ?? 0,
|
||
breadTo: [...(window.__director.taskSetProgress['breadTo'] ?? [])],
|
||
done: [...window.__director.tasksDone],
|
||
canSleep: window.__director.canSleep,
|
||
dlg: window.__director.dialogueActive,
|
||
}));
|
||
await sleep(600);
|
||
|
||
console.log('\n=== A. 面包任务提交 ===');
|
||
// 1. 面包房取面包
|
||
await startScene('BakeryScene');
|
||
await drain();
|
||
// counter_bread 交互区在地图对象里:从 JSON 读坐标
|
||
const cbObj = await ev(() => window.__game.scene.getScene('BakeryScene').interactZones.find(z => z.id === 'counter_bread'));
|
||
console.log('counter_bread zone:', cbObj);
|
||
await setPlayer('BakeryScene', cbObj.x + 40, cbObj.y + 40);
|
||
await setPlayer('BakeryScene', cbObj.x, cbObj.y + 8);
|
||
await tap('KeyE'); await sleep(400);
|
||
const t1 = await drain();
|
||
console.log('取面包对话:', t1);
|
||
console.log('状态:', await dstate());
|
||
|
||
// 2. 送 dabao(plaza)
|
||
await startScene('PlazaScene');
|
||
await drain();
|
||
const dabao = await ev(() => { const s = window.__game.scene.getScene('PlazaScene'); const a = s.actors.find(a => a.def.id === 'dabao'); return { x: a.sprite.x, y: a.sprite.y }; });
|
||
await setPlayer('PlazaScene', dabao.x + 40, dabao.y + 40);
|
||
await setPlayer('PlazaScene', dabao.x, dabao.y + 8);
|
||
await tap('KeyE'); await sleep(400);
|
||
const t2 = await drain();
|
||
console.log('dabao 对话:', t2);
|
||
console.log('状态:', await dstate());
|
||
|
||
// 3. 送 mimi(shop)与 guiyeye(lake)
|
||
await startScene('ShopScene');
|
||
await drain();
|
||
const mimi = await ev(() => { const s = window.__game.scene.getScene('ShopScene'); const a = s.actors.find(a => a.def.id === 'mimi'); return { x: a.sprite.x, y: a.sprite.y }; });
|
||
await setPlayer('ShopScene', mimi.x + 40, mimi.y + 40);
|
||
await setPlayer('ShopScene', mimi.x, mimi.y + 8);
|
||
await tap('KeyE'); await sleep(400);
|
||
console.log('mimi 对话:', await drain());
|
||
console.log('状态:', await dstate());
|
||
|
||
await startScene('LakeScene');
|
||
await drain();
|
||
const gui = await ev(() => { const s = window.__game.scene.getScene('LakeScene'); const a = s.actors.find(a => a.def.id === 'guiyeye'); return { x: a.sprite.x, y: a.sprite.y }; });
|
||
await setPlayer('LakeScene', gui.x + 40, gui.y + 40);
|
||
await setPlayer('LakeScene', gui.x, gui.y + 8);
|
||
await tap('KeyE'); await sleep(400);
|
||
console.log('guiyeye 对话:', await drain());
|
||
console.log('状态:', await dstate());
|
||
|
||
console.log('\n=== B. 第一天睡觉(用户场景:任务未全了结,靠黄昏计时) ===');
|
||
await startScene('HouseScene');
|
||
await drain();
|
||
// 强制黄昏计时,使 canSleep=true(模拟用户等满 5 分钟)
|
||
await ev(() => { window.__director.dayElapsedMs = 300000; });
|
||
console.log('睡前状态:', await dstate());
|
||
// 走到床边按 E
|
||
const bed = await ev(() => window.__game.scene.getScene('HouseScene').interactZones.find(z => z.id === 'bed'));
|
||
await setPlayer('HouseScene', bed.x + 40, bed.y + 40);
|
||
await setPlayer('HouseScene', bed.x, bed.y + 8);
|
||
await tap('KeyE'); await sleep(400);
|
||
console.log('床交互后对话:', await drain());
|
||
// 采样 20 秒:场景序列与卡死点
|
||
for (let i = 0; i < 20; i++) {
|
||
const s = await ev(() => {
|
||
const sm = window.__game.scene;
|
||
return {
|
||
active: sm.getScenes(true).map(sc => sc.scene.key),
|
||
day: window.__director.day,
|
||
dlg: window.__director.dialogueActive,
|
||
uiPayload: (() => { const u = sm.getScene('UIScene'); return u && u.payload ? (u.payload.lines?.[0] ?? '').slice(0, 20) : null; })(),
|
||
};
|
||
});
|
||
console.log(`t+${(i+1)}s`, JSON.stringify(s));
|
||
// 模拟玩家按 E 推进梦境对话
|
||
if (s.uiPayload) { await tap('KeyE'); }
|
||
await sleep(1000);
|
||
}
|
||
console.log('最终状态:', await dstate());
|
||
await browser.close();
|
||
process.exit(0);
|