Files
codex-bot 4845826deb
Shanhe source and offline package checks / verify (pull_request) Failing after 5s
feat: sync Shanhe 2.2 source and add remote package verification
2026-11-01 17:13:46 +08:00

16 lines
3.2 KiB
JavaScript

// Deterministic Node diagnostic, not a mobile FPS / native acceptance test.
const fs=require('node:fs'),vm=require('node:vm'),path=require('node:path'),Module=require('node:module'),{performance}=require('node:perf_hooks'),M=require('matter-js');
const args=process.argv.slice(2),source=args[0]||'src/game.js';
const mod=new Module(path.resolve('src/profile-game.cjs'));mod.filename=path.resolve('src/profile-game.cjs');mod.paths=module.paths;mod._compile(fs.readFileSync(source,'utf8'),mod.filename);const {Game}=mod.exports;
const box={window:{}};vm.runInNewContext(fs.readFileSync('src/maps.js','utf8'),box);const maps=box.window.MAP_DATA.levels;
let county;vm.runInNewContext(fs.readFileSync('src/county/140500.js','utf8'),{window:{PuzzleAtlas:{register(l){county=l;}}}});
const methods=['uprightOnce','guardPenetrations','tryMerges','attractNearby','updateSupport','stepGrowth','limitMotion','pose','pocketPlan','snapPlan'];
function run(level,upright,shake){let seed=74;const rng=()=>{seed=(seed*1664525+1013904223)>>>0;return seed/4294967296;};const g=new Game(level,440,680,4,()=>{},rng,1,2),cost={},calls={},ticks=[],collisions={count:0},transforms={count:0};let measuring=false;
for(const key of methods){const f=g[key];g[key]=function(...args){if(!measuring)return f.apply(this,args);calls[key]=(calls[key]||0)+1;const start=performance.now();try{return f.apply(this,args);}finally{cost[key]=(cost[key]||0)+performance.now()-start;}};}
const collide=M.Collision.collides,angle=M.Body.setAngle;M.Collision.collides=function(...args){if(measuring)collisions.count++;return collide.apply(this,args);};M.Body.setAngle=function(...args){if(measuring)transforms.count++;return angle.apply(this,args);};g.start();let awake=0,samples=0;
try{for(let i=0;i<2400&&g.status==='playing';i++){if(g.pending&&i%35===0){const serial=g.pending.serial;g.movePending(35+rng()*370,serial);g.holdPending(serial);g.releasePending(serial);}if(i===1200)upright&&g.uprightOnce();if(shake&&i>=1200&&i%40===0)g.swipe({x:220,y:560},{x:i%80?100:-100,y:-30},65);measuring=i>=1800;const start=performance.now();g.tick(1000/60);if(measuring){ticks.push(performance.now()-start);awake+=g.groups.filter(p=>!p.body.isSleeping).length;samples+=g.groups.length;}}}finally{M.Collision.collides=collide;M.Body.setAngle=angle;}
ticks.sort((a,b)=>a-b);const result={id:level.id,upright,shake,status:g.status,groups:g.groups.length,dropped:g.dropped,parts:g.groups.reduce((n,p)=>n+p.body.parts.length,0),sampleTicks:ticks.length,meanMs:ticks.reduce((n,t)=>n+t,0)/ticks.length,p95Ms:ticks[Math.floor(ticks.length*.95)],awakeRatio:awake/samples,collisionCalls:collisions.count,angleGeometryTransforms:transforms.count,costMs:cost,calls};g.destroy();return result;
}
const out=[];for(const level of [maps[0],maps.find(l=>l.id==='420000'),county])for(const shake of [false,true])for(const upright of [false,true])out.push(run(level,upright,shake));
const report={scope:'Node physics only; upright means one button press at tick 1200, not a mode; method times are inclusive and instrumentation adds overhead; no rendering/video or native FPS claim',source,cases:out};if(args[1])fs.writeFileSync(args[1],JSON.stringify(report,null,2)+'\n');else console.log(JSON.stringify(report,null,2));