Served with isolation headers; start-screen capability notices; tests on the real GPU (t88 phase 1)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+28
-15
@@ -4,20 +4,19 @@
|
||||
import json, sys, pathlib, re
|
||||
sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent.parent / 'tools'))
|
||||
from use_venv import ensure_playwright; ensure_playwright()
|
||||
from playwright.sync_api import sync_playwright
|
||||
from browser import launch, consume_gpu_option
|
||||
consume_gpu_option()
|
||||
root = pathlib.Path(__file__).resolve().parent.parent
|
||||
out = pathlib.Path(sys.argv[1] if len(sys.argv) > 1 else root / 'shots' / 'play'); out.mkdir(parents=True, exist_ok=True)
|
||||
url = (root / 'dist' / 'index.html').as_uri()
|
||||
fails = []
|
||||
def check(name, cond, extra=''):
|
||||
print(('PASS ' if cond else 'FAIL ') + name + (f' [{extra}]' if extra != '' else ''))
|
||||
if not cond: fails.append(name)
|
||||
|
||||
with sync_playwright() as p:
|
||||
b = p.chromium.launch()
|
||||
ctx = b.new_context(viewport={'width': 1280, 'height': 800})
|
||||
pg = ctx.new_page()
|
||||
with launch(viewport={'width': 1280, 'height': 800}) as (b, pg, url):
|
||||
ctx = pg.context
|
||||
logs = []
|
||||
pg.add_init_script("if (!localStorage.getItem('deepgrain.settings')) localStorage.setItem('deepgrain.settings', JSON.stringify({look:'pixel', sv:2}));")
|
||||
pg.on('pageerror', lambda e: logs.append(f'PAGEERROR: {e}'))
|
||||
pg.on('console', lambda m: logs.append(f'{m.type}: {m.text}') if m.type == 'error' else None)
|
||||
pg.goto(url); pg.evaluate("SET.fog = false"); pg.wait_for_timeout(300)
|
||||
@@ -61,13 +60,13 @@ with sync_playwright() as p:
|
||||
check('Continue loads the migrated seed and playtime', pg.evaluate('worldSeed === 12345 && GAME.playTime >= 3661 && !!GAME.worldId'))
|
||||
pg.evaluate("""() => {
|
||||
window.__pack = packBuffers;
|
||||
packBuffers = async b => { await new Promise(r => setTimeout(r, 600)); return __pack(b); };
|
||||
packBuffers = async b => { await new Promise(r => { window.__finishSave = r; }); return __pack(b); };
|
||||
window.__saving = saveWorld('main', true);
|
||||
}""")
|
||||
pg.locator('#saving').wait_for(state='visible')
|
||||
pg.screenshot(path=str(out / 'saving-progress.png'))
|
||||
check('slow save shows the saving chip', pg.is_visible('#saving'))
|
||||
pg.evaluate('async () => { await __saving; packBuffers = __pack; }')
|
||||
pg.evaluate('async () => { __finishSave(); await __saving; packBuffers = __pack; }')
|
||||
check('saving chip hides when the save ends', not pg.is_visible('#saving'))
|
||||
pg.evaluate('quitToTitle()')
|
||||
names = {}
|
||||
@@ -248,7 +247,8 @@ with sync_playwright() as p:
|
||||
led = ev(camera_offset)
|
||||
check('camera leads toward the pointer when enabled', all(b - a > 2 for a, b in zip(centred, led)), led)
|
||||
pg.mouse.move(*mouse)
|
||||
ev(f'GAME.paused = {json.dumps(paused)}; saveSettings()')
|
||||
# Keep world-to-screen targets fixed after checking both camera modes.
|
||||
ev(f'GAME.paused = {json.dumps(paused)}; SET.cameraLead = false; saveSettings(); snapCamera()')
|
||||
def cell_to_screen(x, y):
|
||||
return ev(f'(() => {{ const dpr = R.canvas.width / innerWidth; const s = worldToScreenPx({x}+0.5, {y}+0.5); return [s.x/dpr, s.y/dpr]; }})()')
|
||||
def blk(bx, by): return cell_to_screen(bx * 4 + 2, by * 4 + 2)
|
||||
@@ -281,7 +281,11 @@ with sync_playwright() as p:
|
||||
# 1. drill: rock breaks loose, nothing enters the bag
|
||||
pg.mouse.move(*cell_to_screen(bx + 6, gy + 3)); settle(900)
|
||||
sx, sy = cell_to_screen(bx + 6, gy + 3)
|
||||
hold(sx, sy, 3500)
|
||||
pg.mouse.move(sx, sy); pg.mouse.down()
|
||||
try:
|
||||
pg.wait_for_function('stats.dug > 20', timeout=15000)
|
||||
finally:
|
||||
pg.mouse.up()
|
||||
settle(700)
|
||||
check('drill digs with the mouse', ev('stats.dug') > 20, ev('stats.dug'))
|
||||
check('drill does not fill the bag', ev('bagTotal') == 0, ev('bagTotal'))
|
||||
@@ -307,7 +311,8 @@ with sync_playwright() as p:
|
||||
|
||||
ev("SET.cardSeconds = 0; $('cards').replaceChildren()") # centred cards cover the mouse work area; discovery was checked above
|
||||
# 2. vacuum, left button: lock onto what you click
|
||||
pg.keyboard.press('2'); settle(100)
|
||||
pg.keyboard.press('2')
|
||||
pg.wait_for_function("GAME.tool === 1 && $('selcard').querySelector('.name')?.textContent === 'Pneumatic nozzle'")
|
||||
check('Pneumatic nozzle card title and width match the selected tool', ev("GAME.tool === 1 && $('selcard').querySelector('.name').textContent === 'Pneumatic nozzle' && $('selcard').firstElementChild.querySelector('.chip').textContent === `width ${GAME.brush[1]}` && !$('selcard').querySelector('.sub .chip')"))
|
||||
check('Pneumatic nozzle name appears in the tool list and hotbar title', ev("TOOLS[1].name === 'Pneumatic nozzle' && $('hotbar').children[1].title.startsWith('Pneumatic nozzle')"))
|
||||
tgt = ev(f'''(() => {{ for (let r = 0; r < 30; r++) for (let dy = -r; dy <= r; dy++) for (let dx = -r; dx <= r; dx++) {{
|
||||
@@ -492,6 +497,7 @@ with sync_playwright() as p:
|
||||
check('Shift lights every loose bag row', ev("blowAllList().every(m => [...$('baglist').querySelectorAll('.bagrow.on .nm')].some(e => e.textContent === MD[m].name))"))
|
||||
pg.screenshot(path=str(out / '03b-blow-all-preview.png'))
|
||||
pg.keyboard.up('Shift'); settle(150)
|
||||
pg.wait_for_function("!$('selcard').querySelector('.vacchoice').textContent.includes('Everything') && document.querySelectorAll('#baglist .bagrow.on').length === 1")
|
||||
check('releasing Shift restores the chosen blow material', ev("$('selcard').querySelector('.vacchoice').textContent.includes(MD[COAL].name) && !$('selcard').querySelector('.vacchoice').textContent.includes('Everything')"))
|
||||
check('releasing Shift lights only coal', ev("(() => { const rows = [...$('baglist').querySelectorAll('.bagrow.on')]; return rows.length === 1 && rows[0].querySelector('.nm').textContent === MD[COAL].name; })()"))
|
||||
bot_at = ev('[bot.x, bot.y]')
|
||||
@@ -1156,6 +1162,12 @@ with sync_playwright() as p:
|
||||
navigator.getGamepads = () => [window.__pad];
|
||||
}''')
|
||||
pg.keyboard.press('1'); settle(100)
|
||||
# The preceding play-through can leave only air below the bot.
|
||||
ev('''() => {
|
||||
GAME.drillTune = 0;
|
||||
const x0 = Math.floor(bot.x + bot.w / 2), y0 = Math.ceil(bot.y + bot.h) + 2;
|
||||
for (let y = y0; y < y0 + 8; y++) for (let x = x0 - 4; x <= x0 + 4; x++) setCell(y * W + x, DIRT, 20, F_NAT);
|
||||
}''')
|
||||
d0 = ev('stats.dug')
|
||||
ev("__pad.axes[3] = 0.9; __pad.buttons[7].pressed = true; __pad.buttons[7].value = 1;")
|
||||
settle(1500)
|
||||
@@ -1206,10 +1218,11 @@ with sync_playwright() as p:
|
||||
pg.keyboard.press('Escape'); settle(150)
|
||||
|
||||
# Fog has its own paused scene; existing play checks keep the whole world visible.
|
||||
fb = p.chromium.launch(args=['--use-gl=angle', '--use-angle=swiftshader', '--enable-unsafe-swiftshader'])
|
||||
fp = fb.new_page(viewport={'width': 1280, 'height': 800})
|
||||
fog_context = b.new_context(viewport={'width': 1280, 'height': 800})
|
||||
fp = fog_context.new_page()
|
||||
if pg.evaluate('!!window.__allowSoftwareGL'):
|
||||
fp.add_init_script('window.__allowSoftwareGL = true')
|
||||
fp.on('pageerror', lambda e: logs.append(f'PAGEERROR(fog): {e}'))
|
||||
fp.add_init_script('window.__allowSoftwareGL = true')
|
||||
fp.goto(url)
|
||||
fp.evaluate('startNewWorld(4242, 512, 384)')
|
||||
fp.wait_for_function('GAME.running')
|
||||
@@ -1318,7 +1331,7 @@ with sync_playwright() as p:
|
||||
check('fog draws in the smooth look', fp.evaluate('R.smoothOn && SM.ok'))
|
||||
check('unseen smooth grains have no terrain shape', fp.evaluate("(() => {const k=(235-R.vy0)*R.bw+300-R.vx0;return R.px[k]===0x04000000 && R.backPx[k]===0 && R.treePx[k]===0 && R.fieldPx[k]===255})()"))
|
||||
fp.screenshot(path=str(out / 'fog-smooth.png'))
|
||||
fb.close()
|
||||
fog_context.close()
|
||||
|
||||
# 11. the largest world from the title screen
|
||||
pg2 = ctx.new_page()
|
||||
|
||||
Reference in New Issue
Block a user