import {buildAudio} from './audio-assets.mjs'; import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { build } from 'file:///G:/项目/NumberSwipe/modes/01-number-stroke/node_modules/esbuild/lib/main.js'; const root = path.dirname(fileURLToPath(import.meta.url)); buildAudio(root); await build({ absWorkingDir: root, entryPoints: ['src/main.mjs'], outfile: 'game.js', bundle: true, format: 'iife', platform: 'neutral', target: 'es2020', minify: true, plugins: [{ name: 'wechat-host', setup(b) { b.onLoad({ filter: /upstream[\\/]ui\.mjs$/ }, args => { let contents = fs.readFileSync(args.path, 'utf8'); contents=contents.replace("from './audio.mjs'", "from '../audio.mjs'"); const originalRules=contents.split('\n').find(line=>line.startsWith('function rulesFor(')); if(!originalRules)throw Error('上游规则文案入口已变化'); contents=contents.replace(originalRules,'const rulesFor=playerRules;'); contents=contents.replace("const $=id=>document.getElementById(id),canvas=$('board'),ctx=canvas.getContext('2d');","const $=id=>document.getElementById(id);let canvas=$('board'),ctx=canvas.getContext('2d'),previewOnly=false;"); contents=contents.replace(" updateTutorial(bad);", " if(previewOnly)return;updateTutorial(bad);"); const hintHandler=contents.split('\n').find(line=>line.startsWith("$('hint').onclick=")); if(!hintHandler)throw Error('上游指路入口已变化'); contents=contents.replace(hintHandler, `$('hint').onclick=()=>{record.hints++;focus=[];const segment=segmentHints.request(level,solution,path);setStatus(segment?'沿半透明光路连接两端;走偏可撤销或重开,正确到达后提示消失。':'已经完成。');draw();};`); contents=contents.replace("function start(i,open=true){", "function start(i,open=true){segmentHints.clear();"); contents=contents.replace("if(level.tutorial&&!bad.length&&!cleared)focus=", "if(false)focus="); contents+=`\nexport function hintView(){const h=segmentHints.view(level,solution,path);return h?{...h,visitedPolygons:polygons.filter(p=>path.includes(p.id)).map(p=>p.p.map(v=>[...v]))}:null;}\n`; contents="import {createHintController} from '../hints.mjs';\nconst segmentHints=createHintController();\n"+contents; contents+=` export function renderLesson(target,l,route,w,h){ const saved={canvas,ctx,level,solution,path,polygons,centers,unit,focus,cleared,channelViews,cellViews}; try{canvas={clientWidth:w,clientHeight:h,get width(){return target.width},set width(v){target.width=v},get height(){return target.height},set height(v){target.height=v}};ctx=target.getContext('2d');level={...l,tutorial:null};solution=[];path=route;focus=[];cleared=false;previewOnly=true;draw();return {centers:Object.fromEntries(centers),channels:channelViews,cells:cellViews};} finally{({canvas,ctx,level,solution,path,polygons,centers,unit,focus,cleared,channelViews,cellViews}=saved);previewOnly=false;} }`; contents="import {rulesFor as playerRules} from '../copy.mjs';\n"+contents; const old = contents.split('\n').find(line => line.startsWith("$('export').onclick=")); if (!old) throw Error('上游导出入口变化,需要重新检查微信适配'); contents = contents.replace(old, `$('export').onclick=()=>{saveRecord();exportRecords({version:pack.version,exportedAt:new Date().toISOString(),clearedIds:completed,records});setStatus('已保存试玩记录。');};`); return { contents: "import {PACK,document,window,localStorage,exportRecords,performance} from '../platform.mjs';\n" + contents, loader: 'js' }; }); } }] }); console.log('Built campaign-200-r2: 200 levels');