public/dev_tools.js

分割 6 / 10 · 元ファイル 964〜1104行付近

原文の連続部分です。長い圧縮行は行の途中で分割する場合があります。全分割を順に連結するとファイル全文になります。

        最後に描けてから: (C&&C.lastDraw)? +((performance.now()-C.lastDraw)/1000).toFixed(1) : null,
        画面に板がある: !!cv,
        板の大きさ: cv? cv.width+'x'+cv.height : null,
        GPU設定: (typeof SETTINGS!=='undefined') ? {全体:!!SETTINGS.gl, 教室:!!SETTINGS.glClass} : null,
        教室の印: document.body.classList.contains('glcOn'),
        止まった関所: (C&&C.why)||null,   // 2026-09-01 K1指示: 描いていない時、どの関所で戻っているか
      };
    }catch(e){ return {読めず:String(e)}; } })(),
    /* ロード画面の失敗記録(2026-08-29 Codex納品キットの依頼)。
       準備が間に合わなかった/例外で落ちた時だけ中身が入る。空なら順調 */
    loadLog:(()=>{ try{ return (window.__HZG_LOADLOG||[]).slice(-12); }catch(e){ return null; } })(),
    /* 音の記録(2026-08-29 K1依頼)。タイトルの曲の頭が壊れる件の断定用。
       時刻・曲の位置・読み込み具合(0〜4)・音量を、下ごしらえから鳴らし終わりまで並べてある。
       読み方: 「鳴らし始めて+○ms」の行で位置が滑らかに進んでいなければ、そこが壊れた瞬間。
       曲の取得の「控えから:true」はキャッシュから来たという意味(タスクキル直後の起動で出る) */
    bgmLog:(()=>{ try{ return (window.__HZG_BGMLOG||[]).slice(-90); }catch(e){ return null; } })(),
    /* プロローグADVの文字送りの記録(2026-09-02 K1指示)。実機で「2文字目から1秒詰まる」件の断定用。
       行ごとに、何文字目が何msに「置かれ」何msに「出た」かが並ぶ。
       読み方:
       ・置いた が26msずつ進んでいない → 本体(JS)がそこで止まっている
       ・置いた は26msずつなのに 出た が飛んでいる → 絵が追いつけていない(描画側)
       ・前のコマから が大きい所 = 画面が止まっていた長さ
       幕が「開きながら」の行は、プロローグの1行目(700msかけて幕を開けている最中) */
    advLog:(()=>{ try{ return (window.__HZG_ADVLOG||[]).slice(-6); }catch(e){ return null; } })(),
    /* 指の操作が何msかかったか(2026-09-02)。10ms以上かかった物だけ載せる。
       文字送りが止まった時刻と重なっていれば、その出来事の処理が犯人 */
    evLog:(()=>{ try{ return (window.__HZG_EVLOG||[]).filter(e=>e.かかった>=10).slice(-24); }catch(e){ return null; } })(),
    /* 浮き文字・吹き出しの位置(2026-09-02 K1報告「一瞬上に行ってまた元の位置に戻る」)。
       直近3秒ぶんを、コマごと・物ごとに並べてある。
       読み方: 同じidの「上」を縦に追う。1コマだけ大きく減って次で戻っていれば、そいつが跳んだ物。
       跳び幅が46px前後なら、盤面の縦のずらし幅と同じ=座標の取り違え */
    /* 押下音の計器(2026-09-03 K1許可)。
       「呼ばれた」に対して「鳴った」が足りない時、その差がどの理由で消えたかが分かる。
       状態別に interrupted や suspended が積まれていれば、音の口が寝ていたのが原因 */
    kmLog:(()=>{ try{ return window.__HZG_KMLOG||null; }catch(e){ return null; } })(),
    /* 曲の出入り(2026-09-03 K1指示)。直近80件。
       「かけようとした」に対して「鳴らし始めた」が無ければ、その次の行に理由が出ている */
    bgmEv:(()=>{ try{ return (window.__HZG_BGMEV||[]).slice(-40); }catch(e){ return []; } })(),
    /* 曲の位置の物差し(2026-09-04 K1指示「計器をたせ」)。0.5秒ごと・直近60秒ぶん。
       読み方: 「位置」を縦に追う。0付近を行ったり来たり=頭が繰り返している /
       同じ数字が続く=止まっている / 1回だけ大きく戻る=ふつうのループの継ぎ目 */
    bgmPos:(()=>{ try{ return (window.__HZG_BGMPOS||[]).slice(-120); }catch(e){ return []; } })(),
    /* 曲の要素自身の出来事。ゲームが頼んでいない再生や頭出しが混ざっていればここに出る */
    bgmElEv:(()=>{ if(!HZG_METERS.on('曲')) return []; try{ return (window.__HZG_BGMEL_EV||[]).slice(-60); }catch(e){ return []; } })(),
    /* 画面が隠れた・戻った時刻(2026-09-04)。今までは合計秒数しか無かった */
    visLog:(()=>{ if(!HZG_METERS.on('画面')) return []; try{ return (window.__HZG_VISLOG||[]).slice(-40); }catch(e){ return []; } })(),
    /* 効果音の計器(2026-09-04 K1指示「どの効果音がどのタイミングで鳴ったか」)。
       直近160件。「幕が画面に」がtrueの行は、K1 STUDIOのロゴが出ている間に鳴った音 */
    seLog:(()=>{ if(!HZG_METERS.on('効果音')) return []; try{ return (window.__HZG_SELOG||[]).slice(-160); }catch(e){ return []; } })(),
    /* 音の口(AudioContext)の顛末(2026-09-05 K1指示)。
       いつ作り、いつresumeを頼み、それが成功したか失敗したか、0.5秒後にどうなっていたか */
    acLog:(()=>{ if(!HZG_METERS.on('音の口')) return []; try{ return (window.__HZG_ACLOG||[]).slice(-120); }catch(e){ return []; } })(),
    /* 物理の重さ(2026-09-06 K1指示「計器足しとけよ」)。発熱の疑いの切り分け用。
       1コマぶんのミリ秒(直近240コマ)・平均・最悪・回したコマ数・
       そのうち何も動いていなかったコマ数・床の物の数・机や壁の数。
       「コマ仕事」(perf.raid)と並べれば、物理が占める割合が出る */
    /* ★スポット計器(2026-09-06 K1指示)。大群予告の曲が鳴らない件**専用**。直ったら消す */
    spotBgm:(()=>{ if(!HZG_METERS.on('スポット')) return []; try{ return (window.__HZG_SPOTBGM||[]).slice(-40); }catch(e){ return []; } })(),
    /* ★スポット計器(2026-09-06 K1指示「スポット計器つけとけ」)。
       床のバスケットボールがつかめない件**専用**。直ったら消す。
       入切の札に関わらず必ず載せる——この件は「記録が残らないこと」が問題なので、
       K1が計器をオフにしていても取りこぼさない */
    spotBall:(()=>{ try{ return (window.__HZG_SPOTBALL||[]).slice(-40); }catch(e){ return []; } })(),
    /* ★【スポット計器 20260912 掴まれたまま】K1報告 gctjwu「佐藤がゾンビに掴まれたまま離されなくなった」。直ったら消す。
       読み方: 「放した」の行=掴んでいない敵に掴まれたままだった(前ならそのまま固まっていた)瞬間。敵の状態と狙いで、どの道で外れたかが分かる */
    spotGrab:(()=>{ try{ return (window.__HZG_SPOTGRAB||[]).slice(-40); }catch(e){ return []; } })(),
    physPerf:(()=>{ if(!HZG_METERS.on('物理')) return null; try{
      const P=window.__HZG_PHYSPERF; if(!P) return null;
      const a=P.ms||[]; const n=a.length||1;
      const sum=a.reduce((x,y)=>x+y,0);
      return {平均ms:+(sum/n).toFixed(2), 最悪ms:+Math.max.apply(null,a.concat([0])).toFixed(2),
        回したコマ数:P.n, 何も動いていないコマ数:P.idle,
        無駄の割合:P.n?(+(P.idle/P.n*100).toFixed(1)+'%'):'-',
        台数:P.台数, 動いている:P.動いている, 机:P.机, 壁:P.壁, バリケード:P.バリケード,
        進めた回数:P.進めた回数, 直近のms:a.slice(-40)};
    }catch(e){ return null; } })(),
    /* 床の物(武器・ボール)の動き(2026-09-06 K1指示「バグ報告に計器足すなりしろ」)。
       0.1秒ごとに、教室か襲撃か・種類・位置・高さ・平面の速さ・回っている速さ・
       材質(空気抵抗/摩擦/跳ね返り)・世界を進めた刻み。K1報告「襲撃で床を滑ってる」の切り分け用。
       両方の場面が同じ一覧に入るので、そのまま並べて見比べられる */
    dropLog:(()=>{ if(!HZG_METERS.on('床の物')) return []; try{ return (window.__HZG_DROPLOG||[]).slice(-260); }catch(e){ return []; } })(),
    /* 起動の一部始終(2026-09-05 K1指示)。触った回数・幕が開いた時刻・判断材料が揃った時刻 */
    bootLog:(()=>{ if(!HZG_METERS.on('起動')) return []; try{ return (window.__HZG_BOOTLOG||[]).slice(-150); }catch(e){ return []; } })(),
    /* 絵が異常に大きくなった記録(2026-09-05 K1報告)。空なら一度も起きていない。
       「誰」がキャラの番号なら席の札の変形が原因、「写した枠」なら測り方(K)が原因 */
    bigLog:(()=>{ if(!HZG_METERS.on('絵の大きさ')) return []; try{ return (window.__HZG_BIG||[]).slice(-12); }catch(e){ return []; } })(),
    /* 今のKと盤面の実幅。上の記録と見比べる基準 */
    glK:(()=>{ try{ const sc=document.getElementById('scene'); if(!sc) return null;
      const r=sc.getBoundingClientRect();
      return {盤面の実幅:Math.round(r.width), K:+(r.width/390).toFixed(3)}; }catch(e){ return null; } })(),
    /* 必殺技の計器(2026-09-03 K1許可)。技の最中と直後3秒の様子。
       「進んだ」がほぼ0のまま続き、「道」が0なら、道が引けずに踏み込んでは戻される痙攣 */
    spLog:(()=>{ try{ const L=(window.__HZG_SPLOG||[]);
      return L.length ? L.slice(-160) : []; }catch(e){ return []; } })(),
    floatLog:(()=>{ try{ const L=(window.__HZG_FLOATLOG||[]);
      /* 跳んだ物だけに絞って載せる(全部載せると報告が太る) */
      const byId={};
      for(const f of L) for(const o of (f.物||[])){ (byId[o.id]=byId[o.id]||[]).push({t:f.t, 上:o.上, 字:o.字}); }
      const out={};
      for(const id in byId){ const a=byId[id]; let mx=0;
        for(let i=1;i<a.length;i++) mx=Math.max(mx, Math.abs(a[i].上-a[i-1].上));
        if(mx>=12) out[id+'('+a[0].字+')  最大'+Math.round(mx)+'px']=a.map(x=>x.上); }
      /* 盤面のずらしが動いていないか(跳びの本命)。値が変わったコマだけ並べる */
      const cam=[]; let pv=null;
      for(const f of L){
        const k=f.盤面の位置+'|'+f.親たち+'/'+f.送り+'/'+f.見える窓のずれ+'/'+f.ずらし+'/'+f.倍率+'/'+f.拡大+'/'+f.縦ずれ+'/'+f.箱の高さ;
        if(k!==pv){ cam.push({t:f.t, 盤面の位置:f.盤面の位置, 親たち:f.親たち, 送り:f.送り,
                              見える窓のずれ:f.見える窓のずれ, ずらし:f.ずらし, 倍率:f.倍率,
                              拡大:f.拡大, 縦ずれ:f.縦ずれ, 箱の高さ:f.箱の高さ}); pv=k; }
      }
      if(cam.length>1) out['★土台が動いた']=cam.slice(0,24);
      else if(cam.length===1) out['★土台は動いていない']=cam[0];
      return Object.keys(out).length? out : {跳んだ物:'なし(直近3秒)'};
    }catch(e){ return null; } })(),
    /* コマ仕事の内訳(2026-08-21): 襲撃ループ/教室ループの自己時間。19ms級の犯人をここで切り分ける */
    perf:(()=>{ try{ const q=a=>{ if(!a||!a.length) return null; const b=a.slice().sort((x,y)=>x-y);
        return {中央:+b[Math.floor(b.length/2)].toFixed(1), 遅い方1割:+b[Math.floor(b.length*0.9)].toFixed(1), 最悪:+b[b.length-1].toFixed(1)}; };
      const P=window.__hzgPerf||{}; return {襲撃ループ:q(P.raid), 教室ループ:q(P.cls)}; }catch(e){ return null; } })(),
    /* 切り替え工程の時刻印(全撤去TODO段0・2026-08-23): 実機のカクつきがどの工程間で起きたかを読む */
    switchLog:(()=>{ try{ return ((window.__hzgPerf||{}).sw||[]).slice(-24); }catch(e){ return null; } })(),
    /* 発熱計(2026-08-23 K1報告): 描画回数/秒と隠れている間の活動。隠れて動いた秒数>0なら異常 */
    heat:(()=>{ try{ const R=window.__heatRing||[]; if(!R.length) return null;
      const last=R.slice(-60);
      const sum=(a,k)=>a.reduce((x,y)=>x+y[k],0);
      const hid=R.filter(x=>x.h);
      return { 直近60秒:{ 教室描画_平均毎秒:+(sum(last,'p')/last.length).toFixed(1),
          教室描画_最大毎秒:Math.max.apply(null,last.map(x=>x.p)),
          戦闘描画_平均毎秒:+(sum(last,'d')/last.length).toFixed(1) },
        隠れていた秒数:hid.length,
        隠れて動いた秒数:hid.filter(x=>x.p>0||x.d>0).length };
    }catch(e){ return null; } })(),
    events:BB_EV.slice(-100) };
  try{
    const js=document.querySelector('script[src*="raid_battle.js"]');
    if(js) rep.jsver=String(js.getAttribute('src')||'').split('?')[1]||'';
  }catch(e){}
  try{ if(typeof game!=='undefined' && game){
    rep.screen={ phase:game.phase, day:game.day, slot:game.slot,
      alive:(game.students||[]).filter(function(s){ return ['healthy','injured','suspect'].indexOf(s.state)>=0; }).length };
    rep.daily=slimDaily(game);
  } }catch(e){ rep.screenErr=String(e).slice(0,120); }