128 lines
4.3 KiB
JavaScript
128 lines
4.3 KiB
JavaScript
// ===== 车库资源预热模块 =====
|
||
// 目的:从战局返回车库时,车库界面要一次性加载大量贴图/图标/坦克模型,
|
||
// 首次全部现场拉取会明显卡顿。这里在**战局空闲时**后台把这些资源拉进浏览器缓存。
|
||
//
|
||
// 预热两批:
|
||
// ① /play/<static/...> —— 车库/大厅 UI 图片(由 resources.json 资源表枚举,本地直出)
|
||
// ② /resources/<...> —— res.3dtank.com 上最近访问过的模型/贴图
|
||
// 清单由本地 serve.js 的 /__prefetch_list__ 提供(按缓存文件 mtime 倒序)
|
||
//
|
||
// 策略:
|
||
// - 只在捕获到 __gameMode__(已在战局)后 8 秒才开始,避开进入战局的加载高峰
|
||
// - 串行 + 间隔限速,避免抢占战局带宽
|
||
// - 10 分钟内只跑一次(localStorage 记录),可用 __hornetPrefetch__.stop() 手动停止
|
||
// - localStorage.hornetPrefetch = '0' 可永久关闭
|
||
|
||
(function () {
|
||
var KEY_AT = 'hornetPrefetchAt';
|
||
var KEY_OFF = 'hornetPrefetch';
|
||
var GAP_STATIC = 40; // UI 图片间隔(ms)
|
||
var GAP_RES = 30; // 模型/贴图间隔(ms)
|
||
|
||
var State = { running: false, stopped: false, timers: [] };
|
||
|
||
function LastRunAt() {
|
||
try { return Number(localStorage.getItem(KEY_AT) || 0) || 0; } catch (e) { return 0; }
|
||
}
|
||
|
||
function MarkRun() {
|
||
try { localStorage.setItem(KEY_AT, String(Date.now())); } catch (e) {}
|
||
}
|
||
|
||
// 串行限速加载;命中缓存的资源不会产生网络请求
|
||
function LoadList(List, Gap, Done) {
|
||
var Index = 0, Ok = 0;
|
||
function Next() {
|
||
if (State.stopped) return;
|
||
if (Index >= List.length) {
|
||
if (Ok > 0) console.log('[预热] 完成 ' + Ok + '/' + List.length + ' 项');
|
||
if (Done) Done();
|
||
return;
|
||
}
|
||
var Url = List[Index++];
|
||
fetch(Url, { cache: 'force-cache' })
|
||
.then(function () { Ok++; })
|
||
.catch(function () {})
|
||
.then(function () { setTimeout(Next, Gap); });
|
||
}
|
||
Next();
|
||
}
|
||
|
||
// ① 车库/大厅 UI 图片:从 webpack 资源表枚举
|
||
function PreloadStatic() {
|
||
fetch('/play/static/js/unpacked/resources.json', { cache: 'force-cache' })
|
||
.then(function (R) { return R.json(); })
|
||
.then(function (Json) {
|
||
var Map = (Json && Json.resourceMap) || {};
|
||
var Seen = {};
|
||
var List = [];
|
||
for (var K in Map) {
|
||
if (!Object.prototype.hasOwnProperty.call(Map, K)) continue;
|
||
var V = Map[K];
|
||
if (typeof V !== 'string' || Seen[V]) continue;
|
||
Seen[V] = 1;
|
||
List.push('/play/' + V);
|
||
}
|
||
console.log('[预热] 车库 UI 资源 ' + List.length + ' 项');
|
||
LoadList(List, GAP_STATIC, PreloadRes);
|
||
})
|
||
.catch(function () { PreloadRes(); });
|
||
}
|
||
|
||
// ② res.3dtank.com 资源:按本地缓存清单(最近访问优先)
|
||
function PreloadRes() {
|
||
fetch('/__prefetch_list__?n=600')
|
||
.then(function (R) { return R.json(); })
|
||
.then(function (Json) {
|
||
var List = (Json && Json.list) || [];
|
||
if (!List.length) return;
|
||
console.log('[预热] 战局/车库资源 ' + List.length + ' 项');
|
||
LoadList(List, GAP_RES, null);
|
||
})
|
||
.catch(function () {});
|
||
}
|
||
|
||
function Run() {
|
||
if (State.stopped) return;
|
||
if (Date.now() - LastRunAt() < 10 * 60 * 1000) return; // 10 分钟内只跑一次
|
||
MarkRun();
|
||
PreloadStatic();
|
||
}
|
||
|
||
function _start() {
|
||
if (State.running) return;
|
||
State.running = true;
|
||
State.stopped = false;
|
||
|
||
try {
|
||
if (localStorage.getItem(KEY_OFF) === '0') {
|
||
console.log('[预热] 已被 localStorage.hornetPrefetch=0 关闭');
|
||
State.running = false;
|
||
return;
|
||
}
|
||
} catch (e) {}
|
||
|
||
console.log('===== 车库资源预热启动 =====');
|
||
|
||
// 等进入战局:__gameMode__ 由 hook_gamemode.js 捕获
|
||
var Wait = setInterval(function () {
|
||
if (State.stopped) { clearInterval(Wait); return; }
|
||
if (!window.__gameMode__) return;
|
||
clearInterval(Wait);
|
||
setTimeout(Run, 8000);
|
||
}, 2000);
|
||
State.timers.push(Wait);
|
||
|
||
window.__hornetPrefetch__ = {
|
||
running: true,
|
||
stop: function () {
|
||
State.stopped = true;
|
||
for (var I = 0; I < State.timers.length; I++) clearInterval(State.timers[I]);
|
||
console.log('[预热] 已停止');
|
||
}
|
||
};
|
||
}
|
||
|
||
_start();
|
||
})();
|