import { DEV } from 'cc/env'; /** * 线上诊断:仅白名单 tag 上传平台(pfLog + RealtimeLogManager)。 * 其余只打 DEV console,避免误报占满后台配额。 * 单条 ≤256 字符;同 key 默认 10 分钟冷却。 */ export class PfDiagnostics { private static _realtime: { error?: (m: string) => void; warn?: (m: string) => void; info?: (m: string) => void; log?: (m: string) => void } | null = null; private static _filterReady = false; private static _lastMsByKey: Record = {}; /** 仅这些 key 实际上传抖音/微信日志后台(预警波次类 WARN 仅本地,不上传) */ private static readonly PLATFORM_UPLOAD_KEYS = new Set([ 'BATTLE:STUCK_PAUSE', 'SETTLE:OPEN_FAIL', 'SKILL:OPEN_FAIL', 'SKILL:OPEN_RELOAD', 'STACK:BLOCK_STACK', 'STACK:PIN_COLLAPSE', 'MEM:WARN', ]); private static _realtimeLogger() { if (this._realtime !== null) return this._realtime; const pf = gg?.sdk?.pf ?? (typeof globalThis !== 'undefined' ? (globalThis as any).tt : null); if (!pf?.getRealtimeLogManager) { this._realtime = null; return null; } try { const logger = pf.getRealtimeLogManager({ syncToConsole: !!DEV }); if (!this._filterReady) { logger.addFilterMsg?.('xxfkz'); this._filterReady = true; } this._realtime = logger; } catch { this._realtime = null; } return this._realtime; } private static _battlePrefix(): string { const b = gg.game?.CurentBattle; const ch = b?.getReportDYChapterId?.() ?? gg.data?.doc?.chapter ?? 0; const wave = b?.CurentWaveNum ?? 0; return `ch${ch}_w${wave}`; } static shouldUploadPlatform(domain: string, tag: string): boolean { return this.PLATFORM_UPLOAD_KEYS.has(`${domain}:${tag}`); } /** @returns 是否实际上传平台(冷却或未在白名单会返回 false) */ static write( domain: string, tag: string, detail: string, cooldownMs = 600000, level: 'error' | 'warn' | 'info' = 'warn', ): boolean { const key = `${domain}:${tag}`; const upload = this.shouldUploadPlatform(domain, tag); let msg = `${this._battlePrefix()}-${domain}-${tag}-${detail}`; if (msg.length > 250) msg = msg.slice(0, 250); if (DEV) { console.warn('[PfDiag]', upload ? msg : `[local-only] ${msg}`); } if (!upload) return false; const now = Date.now(); const last = this._lastMsByKey[key] ?? 0; if (now - last < cooldownMs) return false; this._lastMsByKey[key] = now; try { gg.sdk?.pfLogKey?.(`${domain}:${tag}`, detail, cooldownMs); } catch { /* ignore */ } return true; } /** 离开战斗回大厅:清掉战斗域诊断冷却,新局可重新上报 */ static resetBattleSession(): void { const battleDomains = new Set(['BATTLE', 'STACK', 'SETTLE', 'SKILL']); for (const key of Object.keys(this._lastMsByKey)) { if (battleDomains.has(key.split(':')[0] ?? '')) { delete this._lastMsByKey[key]; } } } }