[性能/资源] 优化首屏加载耗时与资源体积(.r8 实体图集无损压缩、首帧关键路径解耦与按需懒加载) #505
Loading…
Reference in New Issue
No description provided.
Delete Branch "%!s(<nil>)"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
背景与问题描述 (Background & Problem Statement)
随着全 5 幕关卡、7 大职业、全量怪物、技能飞弹、光环覆盖层与 UI 面板资源的持续完善,网页端首次打开进入游戏(
boot()->runScene()->loop.start())需要加载的资源体积越来越大,首屏等待时间明显变长。经全链路实测诊断,当前打开网页加载缓慢主要由以下 5 个核心瓶颈 叠加导致:
.r8实体图集未压缩裸传samples/d2-packs/entities/共 648.98 MB(单个角色char-so.r87.9 MB、char-dz.r812.3 MB;单个怪物如monster-0e-hth.r8高达 23.2 MB)scripts/pack-entity-assets.ts将 8-bit 调色板索引直存为未压缩.r8裸字节数组(含大量透明像素0),Vite 开发服与普通静态托管均不对.r8后缀启用流式压缩。实测仅做无损 Gzip 即可从 648.98 MB 降至 83.44 MB(缩减 87.1%,立省 565.5 MB)。loop.start()必须等待 10+ 个串行步骤 全部完成才画出第一帧src/scene/act-scene.ts(第 7886–9499 行)中,主循环启动前串行阻塞等待:同步解析全量掉落表 TSV -> 地图全部objectPages-> 小地图图集 -> 全部 40 张 UI PNG(含未打开的背包/角色/储物箱/赫拉迪克方块/任务/传送站/商店底图) -> 当前关卡所有怪物种类的巨型.r8图集 -> 角色.r8图集。act-scene.ts(第 7352–7362 行)在runScene()开头立即全量拉取所有飞弹(public/missiles19 MB)和所有光环/诅咒覆盖层(public/overlays19 MB);src/ui/hud-manager.ts(第 431–433 行)立即拉取全部 30 个技能图标与技能树背景图(public/skills3.5 MB),严重挤占 HTTP 连接池与地图/主角的关键带宽。BAKED_UI_MANIFEST(684 KB)已打包进 JS(src/ui/baked-ui-meta.ts),但HudManager.init()仍通过网络请求/ui/manifest.json(703 KB);②
/ui/items-atlas.png(702 KB)在HudManager.init()与loadItemsAtlas()中被重复请求并上传 GPU 两次;③
index.json(204 KB)在populatePackSelectors()(act-scene.ts:9594)中未走getPackIndex()缓存,被拉取两次;④
minimap.loadAtlases(renderer, "/automap")(src/ui/minimap.ts:228-246)对 8 张小地图先请求不存在的/automap/*.png触发 8 次 404 后才回退到/ui/automap-*.png。acts.js1.3 MB +embedded-drop-tables.js1.2 MB +skill-calc-engine.js306 KB)act-scene.ts:9985在发起任何网络请求前,先在主线程同步调用getEmbeddedDropTables()将 1.1 MB 的原始 TSV 字符串用TextEncoder编码并解析成掉落表与商店表,阻塞首屏网络请求发起。核心需求与设计方案 (Requirements & Proposed Design)
阶段 1:消除重复请求、404 探测���主线程同步阻塞
BAKED_UI_MANIFEST,消除/ui/manifest.json(703 KB)网络请求:HudManager.init()(src/ui/hud-manager.ts:422-429)直接使用已导入的BAKED_UI_MANIFEST,不再发起fetch("/ui/manifest.json")。items-atlas.png(702 KB),消除重复下载与双份 GPU 纹理:HudManager与act-scene.ts(loadItemsAtlas)的物品图集加载入口,复用单份 GPU 纹理与ImageBitmap。index.json(204 KB)二次拉取:populatePackSelectors()(src/scene/act-scene.ts:9594)中的fetchJson改为调用带内存缓存的getPackIndex(packBase)。minimap.loadAtlases(renderer, "/ui")首选路径对齐为实际存放目录/ui/automap-*.png,消除每次进图 8 个/automap/automap-*.png的 404 报错。getEmbeddedDropTables()移出首屏网络请求前的同步阻塞点并动态分包:loadPackRuntime()网络请求;将embedded-drop-tables.ts(1.2 MB)改为异步并行加载或在首帧渲染后初始化,使首包 JS 体积减少 1.2 MB。阶段 2:
.r8实体图集 Gzip 无损压缩存储与流式解压(缩减 87.1% 实体体积).r8存储 8-bit 原始调色板索引(gl.R8),用于片元着色器精确执行 Act 调色板映射与invColormap(Boss 染色、冰冻/中毒/石化色调偏移)。scripts/pack-entity-assets.ts写出.r8时采用zlib.gzipSync(packed.r8, { level: 6 })无损压缩:char-so.r8:7.90 MB -> 1.55 MB(缩小 80.4%)monster-0e-hth.r8:23.24 MB -> 1.98 MB(缩小 91.5%)samples/d2-packs/entities/总体积:648.98 MB -> 83.44 MB(节省 565.53 MB)src/scene/act-scene.ts的fetchR8Sheet()中检测 Gzip 魔数(0x1f 0x8b),通过浏览器原生DecompressionStream("gzip")解压为Uint8Array(同时向下兼容未压缩.r8),并严格校验解压后byteLength === width * height。scripts/verify-entity-packs.ts支持检测 Gzip 魔数并解压校验尺寸与像素契约。阶段 3:首屏渲染关键路径解耦(毫秒级进入游戏画面)
runtime.loadPages()优先加载priorityPages(出生点首屏视口所需的地板与墙壁图集页),不再让全图所有objectPages阻塞首屏视口地板页;其余图集页在首帧后后台补齐。runScene()开头即并行发起当前主角的loadCharacterArt()请求;loadMonsterArtMap()改为后台流式加载(每加载完一种怪物立即渲染上屏),不阻塞主角与地图的首帧呈现(同时保证无头浏览器验证脚本的确定性等待契约)。ctrl-panel.png)、生命/法力球(orbs.png)、字体与状态图标;char-sheet.png、inv-sheet.png、stash-bg.png、cube-bg.png、quest-bg.png、quests-atlas.png、waypoint-bg.png、vendor-bg.png)移至首帧渲染后后台加载或首次打开面板时等待。阶段 4:消除启动请求风暴——飞弹(19 MB)与覆盖层(19 MB)按需懒加载
missiles/19 MB)按需加载:runScene()启动时全量拉取MISSILE_METAS的逻辑;封装ensureMissileArtLoaded()(带请求去重 Promise 缓存),在释放/装备对应技能时按需加载,首帧后仅预热当前绑定的初始技能飞弹。overlays/19 MB)按需加载:runScene()启动时全量拉取OVERLAY_METAS的逻辑;封装ensureOverlayArtLoaded(),在触发triggerOverlay()或光环状态时按需加载。skills/icon_*.png)按需加载:预期收益与验收标准 (Acceptance Criteria)
samples/d2-packs/entities/磁盘与传输体积从 ~649 MB 降至 ~83 MB(缩减 >85%),且npm run verify:entity-packs校验 100% 通过。/ui/manifest.json、/ui/items-atlas.png、index.json的重复网络请求,消除小地图/automap/*.png的 8 次 404 请求。firstFrameMs且不影响战斗与面板交互。npm test、npm run verify:acts、npm run verify:animation、npm run verify:ground-browser)100% 通过,严格保持 1.13c 视觉与逻辑对齐。