modelstage 0.0.0-stage → 0.5.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (281) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +274 -2
  3. package/THIRD_PARTY_NOTICES.md +90 -0
  4. package/bin/modelstage.mjs +137 -0
  5. package/config/diag-upload.example.json +7 -0
  6. package/config/models/live2d.assetbundls.json +1 -0
  7. package/config/models/live2d.azurlane.json +1 -0
  8. package/config/models/live2d.azurlane_bundle.json +1 -0
  9. package/config/models/live2d.azurlane_spine.json +1 -0
  10. package/config/models/live2d.bd2.json +1 -0
  11. package/config/models/live2d.bluearchive.json +1 -0
  12. package/config/models/live2d.live2d.json +1 -0
  13. package/config/models/live2d.nikke.json +1 -0
  14. package/config/models/live2d.nikke_2.json +1 -0
  15. package/config/models/live2d.npc.json +1 -0
  16. package/config/models/spine.assetbundls.json +1 -0
  17. package/config/models/spine.azurlane.json +1 -0
  18. package/config/models/spine.azurlane_bundle.json +1 -0
  19. package/config/models/spine.azurlane_spine.json +1 -0
  20. package/config/models/spine.bd2.json +1 -0
  21. package/config/models/spine.bluearchive.json +1 -0
  22. package/config/models/spine.live2d.json +1 -0
  23. package/config/models/spine.nikke.json +1 -0
  24. package/config/models/spine.nikke_2.json +1 -0
  25. package/config/models/spine.npc.json +1 -0
  26. package/config/names/NIKKE.json +1058 -0
  27. package/config/names/README.md +47 -0
  28. package/config/names//345/244/251/345/221/275/344/271/213/345/255/220.json +42897 -0
  29. package/config/names//346/243/225/350/211/262/345/260/230/345/237/2032.json +4016 -0
  30. package/config/names//347/242/247/350/223/235/350/210/252/347/272/277.json +38342 -0
  31. package/config/plugins.json +13 -0
  32. package/config/resources.example.json +40 -0
  33. package/package.json +63 -4
  34. package/plugins/unity-live2d-bundle/README.md +98 -0
  35. package/plugins/unity-live2d-bundle/index.js +891 -0
  36. package/plugins/unity-live2d-bundle/lib/anim-to-motion.js +402 -0
  37. package/plugins/unity-live2d-bundle/lib/bundle-probe.js +244 -0
  38. package/plugins/unity-live2d-bundle/lib/bytes.js +189 -0
  39. package/plugins/unity-live2d-bundle/lib/common-strings.js +46 -0
  40. package/plugins/unity-live2d-bundle/lib/dxt.js +197 -0
  41. package/plugins/unity-live2d-bundle/lib/errors.js +71 -0
  42. package/plugins/unity-live2d-bundle/lib/etc2.js +371 -0
  43. package/plugins/unity-live2d-bundle/lib/extract.js +242 -0
  44. package/plugins/unity-live2d-bundle/lib/lzma-d-min.LICENSE.txt +21 -0
  45. package/plugins/unity-live2d-bundle/lib/lzma-d-min.js +34 -0
  46. package/plugins/unity-live2d-bundle/lib/model3.js +137 -0
  47. package/plugins/unity-live2d-bundle/lib/png.js +424 -0
  48. package/plugins/unity-live2d-bundle/lib/serialized.js +233 -0
  49. package/plugins/unity-live2d-bundle/lib/texdecode.js +190 -0
  50. package/plugins/unity-live2d-bundle/lib/typetree.js +215 -0
  51. package/plugins/unity-live2d-bundle/lib/unityfs.js +396 -0
  52. package/plugins/unity-live2d-bundle/plugin.json +81 -0
  53. package/plugins/unity-live2d-bundle/profiles/unityfs-live2d.json +26 -0
  54. package/plugins/unity-spine-bundle/index.js +535 -0
  55. package/plugins/unity-spine-bundle/lib/bytes.js +189 -0
  56. package/plugins/unity-spine-bundle/lib/common-strings.js +46 -0
  57. package/plugins/unity-spine-bundle/lib/dxt.js +197 -0
  58. package/plugins/unity-spine-bundle/lib/errors.js +79 -0
  59. package/plugins/unity-spine-bundle/lib/etc2.js +371 -0
  60. package/plugins/unity-spine-bundle/lib/extract.js +242 -0
  61. package/plugins/unity-spine-bundle/lib/lzma-d-min.LICENSE.txt +21 -0
  62. package/plugins/unity-spine-bundle/lib/lzma-d-min.js +34 -0
  63. package/plugins/unity-spine-bundle/lib/png.js +424 -0
  64. package/plugins/unity-spine-bundle/lib/serialized.js +233 -0
  65. package/plugins/unity-spine-bundle/lib/texdecode.js +190 -0
  66. package/plugins/unity-spine-bundle/lib/typetree.js +215 -0
  67. package/plugins/unity-spine-bundle/lib/unityfs.js +396 -0
  68. package/plugins/unity-spine-bundle/plugin.json +75 -0
  69. package/src/server/README.md +69 -0
  70. package/src/server/assets/browse.mjs +56 -0
  71. package/src/server/assets/bundle-probe.mjs +94 -0
  72. package/src/server/assets/probe.mjs +184 -0
  73. package/src/server/core/config.mjs +173 -0
  74. package/src/server/core/env-num.mjs +60 -0
  75. package/src/server/core/env.mjs +49 -0
  76. package/src/server/core/fs-portable.mjs +37 -0
  77. package/src/server/core/log.mjs +107 -0
  78. package/src/server/core/paths.mjs +44 -0
  79. package/src/server/data/catalog.mjs +1091 -0
  80. package/src/server/data/entry-states.mjs +499 -0
  81. package/src/server/data/live2d.mjs +272 -0
  82. package/src/server/data/manifest-cache.mjs +58 -0
  83. package/src/server/data/manifest-stamp.mjs +135 -0
  84. package/src/server/data/model-meta.mjs +114 -0
  85. package/src/server/data/names.mjs +106 -0
  86. package/src/server/data/shape-probe-worker.mjs +33 -0
  87. package/src/server/data/shape-probe.mjs +626 -0
  88. package/src/server/data/spine.mjs +336 -0
  89. package/src/server/data/tree.mjs +126 -0
  90. package/src/server/http/atomic-json.mjs +145 -0
  91. package/src/server/http/background-solids.mjs +270 -0
  92. package/src/server/http/backgrounds.mjs +388 -0
  93. package/src/server/http/diag-upload.mjs +264 -0
  94. package/src/server/http/diag.mjs +173 -0
  95. package/src/server/http/ready.mjs +167 -0
  96. package/src/server/http/static.mjs +312 -0
  97. package/src/server/http/write.mjs +654 -0
  98. package/src/server/index.mjs +114 -0
  99. package/src/server/plugins/builtin-providers.json +30 -0
  100. package/src/server/plugins/registry.mjs +650 -0
  101. package/src/server/plugins/slot-catalog.mjs +286 -0
  102. package/src/server/routes/background-solids.mjs +56 -0
  103. package/src/server/routes/backgrounds.mjs +77 -0
  104. package/src/server/routes/config.mjs +38 -0
  105. package/src/server/routes/data.mjs +313 -0
  106. package/src/server/routes/diag.mjs +37 -0
  107. package/src/server/routes/entries.mjs +170 -0
  108. package/src/server/routes/ready.mjs +122 -0
  109. package/src/server/serve.mjs +396 -0
  110. package/src/server/unpack/capacity.mjs +217 -0
  111. package/src/server/unpack/mem-probe.mjs +27 -0
  112. package/src/server/unpack/plugin-runner.mjs +529 -0
  113. package/src/server/unpack/plugin-store.mjs +736 -0
  114. package/src/server/unpack/probe-store.mjs +73 -0
  115. package/src/server/unpack/routes.mjs +359 -0
  116. package/src/server/unpack/runtime/exec.mjs +558 -0
  117. package/src/server/unpack/runtime/index.mjs +141 -0
  118. package/src/server/unpack/runtime/node-vm.mjs +111 -0
  119. package/src/server/unpack/unpack-worker.mjs +105 -0
  120. package/src/server/unpack/worker-client.mjs +184 -0
  121. package/src/server/unpack/write-result.mjs +84 -0
  122. package/src/shared/bundle-shape.mjs +83 -0
  123. package/src/shared/entry-reasons.mjs +119 -0
  124. package/src/shared/names.mjs +45 -0
  125. package/src/shared/type-labels.mjs +31 -0
  126. package/src/web/README.md +193 -0
  127. package/src/web/app/anim-list.js +222 -0
  128. package/src/web/app/background-solids.js +150 -0
  129. package/src/web/app/backgrounds.js +152 -0
  130. package/src/web/app/camera-log.js +28 -0
  131. package/src/web/app/context.js +72 -0
  132. package/src/web/app/dir-picker.js +242 -0
  133. package/src/web/app/entry-report.js +71 -0
  134. package/src/web/app/memory-bars.js +91 -0
  135. package/src/web/app/memory-budget.js +228 -0
  136. package/src/web/app/memory-guard.js +204 -0
  137. package/src/web/app/model-actions.js +682 -0
  138. package/src/web/app/renderer-setting.js +70 -0
  139. package/src/web/app/root-manager.js +254 -0
  140. package/src/web/app/status.js +138 -0
  141. package/src/web/app/topbar-actions.js +357 -0
  142. package/src/web/app/transport-actions.js +297 -0
  143. package/src/web/app/ui-state.js +559 -0
  144. package/src/web/app/url-params.js +171 -0
  145. package/src/web/app/view-settings.js +186 -0
  146. package/src/web/components.css +524 -0
  147. package/src/web/debug/diag-hud.js +95 -0
  148. package/src/web/debug/drag.js +369 -0
  149. package/src/web/debug/log.js +320 -0
  150. package/src/web/debug/model-cmp.js +292 -0
  151. package/src/web/debug/panel.css +474 -0
  152. package/src/web/debug/panel.js +712 -0
  153. package/src/web/debug/race-probe.js +82 -0
  154. package/src/web/debug/upload.js +130 -0
  155. package/src/web/engine/adapters/atlas.js +47 -0
  156. package/src/web/engine/adapters/index.js +22 -0
  157. package/src/web/engine/adapters/renderer.js +223 -0
  158. package/src/web/engine/adapters/skeleton.js +105 -0
  159. package/src/web/engine/adapters/texture.js +64 -0
  160. package/src/web/engine/animation.js +181 -0
  161. package/src/web/engine/appearance.js +136 -0
  162. package/src/web/engine/camera-adapter.js +212 -0
  163. package/src/web/engine/effect-chain.js +138 -0
  164. package/src/web/engine/engine-state.js +120 -0
  165. package/src/web/engine/filters.js +224 -0
  166. package/src/web/engine/fit.js +197 -0
  167. package/src/web/engine/frame-gate.js +33 -0
  168. package/src/web/engine/gl-driver.js +56 -0
  169. package/src/web/engine/gl.js +77 -0
  170. package/src/web/engine/index.js +20 -0
  171. package/src/web/engine/loader.js +55 -0
  172. package/src/web/engine/model-info.js +26 -0
  173. package/src/web/engine/pipeline.js +200 -0
  174. package/src/web/engine/player.js +427 -0
  175. package/src/web/engine/pma/blend.js +76 -0
  176. package/src/web/engine/pma/detect.js +118 -0
  177. package/src/web/engine/pma/index.js +8 -0
  178. package/src/web/engine/pma/resolve.js +112 -0
  179. package/src/web/engine/pma/upload.js +127 -0
  180. package/src/web/engine/pma.js +5 -0
  181. package/src/web/engine/render-frame.js +93 -0
  182. package/src/web/engine/runtime-capabilities.js +209 -0
  183. package/src/web/engine/runtime.js +37 -0
  184. package/src/web/engine/skins.js +165 -0
  185. package/src/web/engine/textures.js +174 -0
  186. package/src/web/index.html +117 -0
  187. package/src/web/infra/api.js +531 -0
  188. package/src/web/infra/diag.js +509 -0
  189. package/src/web/infra/document.js +269 -0
  190. package/src/web/infra/dom.js +31 -0
  191. package/src/web/infra/events.mjs +27 -0
  192. package/src/web/infra/log.js +153 -0
  193. package/src/web/infra/mem-stats.js +112 -0
  194. package/src/web/infra/plugin-host-registration.mjs +285 -0
  195. package/src/web/infra/plugin-host-report.mjs +32 -0
  196. package/src/web/infra/plugin-host-unload.mjs +79 -0
  197. package/src/web/infra/plugin-host-unpack.mjs +899 -0
  198. package/src/web/infra/plugin-host-warmup.mjs +180 -0
  199. package/src/web/infra/plugin-host.js +628 -0
  200. package/src/web/infra/ready.js +461 -0
  201. package/src/web/infra/schedule.js +51 -0
  202. package/src/web/infra/shortcuts.js +129 -0
  203. package/src/web/infra/slot-registry.js +402 -0
  204. package/src/web/infra/vfs.js +247 -0
  205. package/src/web/live2d/bridge.js +400 -0
  206. package/src/web/live2d/model.js +321 -0
  207. package/src/web/live2d/overlay.js +142 -0
  208. package/src/web/live2d/pixi-app.js +111 -0
  209. package/src/web/live2d/playback-probe.js +92 -0
  210. package/src/web/live2d/probe-geometry.js +329 -0
  211. package/src/web/live2d/probe.js +119 -0
  212. package/src/web/live2d/release.js +66 -0
  213. package/src/web/live2d/runtime-adapter.js +289 -0
  214. package/src/web/live2d/stage-ctx.js +152 -0
  215. package/src/web/live2d/stage.js +204 -0
  216. package/src/web/live2d/vfs-settings.js +174 -0
  217. package/src/web/live2d/view.js +89 -0
  218. package/src/web/main.js +629 -0
  219. package/src/web/panel/background-list.js +373 -0
  220. package/src/web/panel/bg-source.js +291 -0
  221. package/src/web/panel/color-picker.css +199 -0
  222. package/src/web/panel/color-picker.js +278 -0
  223. package/src/web/panel/dialog.css +116 -0
  224. package/src/web/panel/dialog.js +173 -0
  225. package/src/web/panel/dom.js +35 -0
  226. package/src/web/panel/icons.js +58 -0
  227. package/src/web/panel/memory-bar.js +195 -0
  228. package/src/web/panel/panel-settings.js +1263 -0
  229. package/src/web/panel/panel.css +1304 -0
  230. package/src/web/panel/render-choice.js +104 -0
  231. package/src/web/panel/schema.js +784 -0
  232. package/src/web/panel/settings-io.js +291 -0
  233. package/src/web/panel/shell-controls.js +274 -0
  234. package/src/web/panel/slider.js +210 -0
  235. package/src/web/panel/toolbar-schema.js +111 -0
  236. package/src/web/panel/toolbar.js +195 -0
  237. package/src/web/panel/transport-picker.js +375 -0
  238. package/src/web/panel/transport.js +321 -0
  239. package/src/web/panel/view.js +553 -0
  240. package/src/web/plugin/unpack-worker.js +185 -0
  241. package/src/web/render/camera/constants.js +60 -0
  242. package/src/web/render/camera/index.js +123 -0
  243. package/src/web/render/camera/spine.js +124 -0
  244. package/src/web/render/capture.js +30 -0
  245. package/src/web/render/interaction.js +527 -0
  246. package/src/web/render/live2d.js +627 -0
  247. package/src/web/render/playback.js +47 -0
  248. package/src/web/render/reset-view.js +29 -0
  249. package/src/web/render/spine.js +386 -0
  250. package/src/web/render/surface-switch.js +176 -0
  251. package/src/web/render/surface.js +571 -0
  252. package/src/web/render/surfaces.js +70 -0
  253. package/src/web/roster/filter.js +31 -0
  254. package/src/web/roster/list.js +276 -0
  255. package/src/web/roster/persist.js +92 -0
  256. package/src/web/roster/reveal.js +77 -0
  257. package/src/web/roster/rows.js +248 -0
  258. package/src/web/roster/snapshot.js +39 -0
  259. package/src/web/roster/type-filter.js +97 -0
  260. package/src/web/roster/view.js +761 -0
  261. package/src/web/spine/canvas-api-groups.js +267 -0
  262. package/src/web/spine/canvas-api.js +97 -0
  263. package/src/web/spine/canvas-document.js +80 -0
  264. package/src/web/spine/canvas-engine.js +193 -0
  265. package/src/web/spine/canvas-entry.js +28 -0
  266. package/src/web/spine/canvas-pixels.js +36 -0
  267. package/src/web/spine/canvas-runtime.js +127 -0
  268. package/src/web/spine/canvas-view.js +108 -0
  269. package/src/web/spine/canvas.js +7 -0
  270. package/src/web/spine/runtime-hint.js +73 -0
  271. package/src/web/spine/runtimes.js +212 -0
  272. package/src/web/style.css +493 -0
  273. package/tool/lib/bundle-probe-node.mjs +121 -0
  274. package/tool/lib/paths.mjs +20 -0
  275. package/tool/lib/runtime-guides.mjs +65 -0
  276. package/tool/lib/runtime-package.mjs +403 -0
  277. package/tool/lib/spine-meta.mjs +227 -0
  278. package/tool/lib/spine-motions.mjs +104 -0
  279. package/tool/parse-jsonc.mjs +86 -0
  280. package/tool/resolve-live2d-runtimes.mjs +276 -0
  281. package/tool/spine-motion-rules.json +101 -0
@@ -0,0 +1,189 @@
1
+ // ============================================================================
2
+ // plugins/unity-live2d-bundle/lib/bytes.js —— 二进制读取原语
3
+ //
4
+ // 职责:在 ArrayBuffer/Uint8Array 上做**小端**定长读取、变长字符串、对齐、hex/sha256。
5
+ // Unity 的资源文件一律小端(本插件暂不支持大端序列化文件,遇到就抛可读错误)。
6
+ //
7
+ // 设计要点:
8
+ // · 只用 DataView + Uint8Array(浏览器与 Node 都有),零依赖。
9
+ // · 位置(pos)显式可读写:容器格式里有大量「先跳到某处再读」的写法。
10
+ // · 64 位整数统一用 Number 返回 —— 本插件只处理「文件内偏移/长度」这类远小于 2^53 的值;
11
+ // 读到的值超出安全整数范围时抛可读错误,避免静默精度丢失。
12
+ // · sha256 分两种实现:有 WebCrypto 用 crypto.subtle(浏览器/https),否则用宿主注入的实现
13
+ // (Node 侧自检脚本会注入 node:crypto)。二者都不可用时返回 null,由调用方决定是否算校验失败。
14
+ //
15
+ // 挂载:globalThis.__ULB__ = { bytes: {...} }(浏览器与 Node 自检脚本都走同一入口)
16
+ // ============================================================================
17
+
18
+ 'use strict';
19
+
20
+ {
21
+ const root = globalThis; // 原 IIFE 的 root 引用(脚本级裸块内保持同名)
22
+ const NS = (root.__ULB__ = root.__ULB__ || {});
23
+
24
+ const HEX = '0123456789abcdef';
25
+
26
+ // CRC32(多项式 0xEDB88320,初值/末值取反)——与 zlib.crc32 一致。
27
+ // 用途:Unity 的动画绑定把「属性路径」存成 32 位哈希,本插件用 CRC32 反查名字
28
+ // (实测 crc32('Value') = 3702945584,正是本样本所有绑定的 attribute 值)。
29
+ const CRC_TABLE = (() => {
30
+ const t = new Uint32Array(256);
31
+ for (let n = 0; n < 256; n++) {
32
+ let c = n;
33
+ for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
34
+ t[n] = c >>> 0;
35
+ }
36
+ return t;
37
+ })();
38
+
39
+ /** 字符串(UTF-8)的 CRC32,返回无符号 32 位整数 */
40
+ function crc32(str) {
41
+ const u8 = new TextEncoder().encode(str);
42
+ let c = 0xffffffff;
43
+ for (let i = 0; i < u8.length; i++) c = CRC_TABLE[(c ^ u8[i]) & 0xff] ^ (c >>> 8);
44
+ return (c ^ 0xffffffff) >>> 0;
45
+ }
46
+
47
+ /** 字节数组 → 十六进制小写串 */
48
+ function toHex(u8) {
49
+ let s = '';
50
+ for (let i = 0; i < u8.length; i++) s += HEX[u8[i] >> 4] + HEX[u8[i] & 15];
51
+ return s;
52
+ }
53
+
54
+ function concatBytes(list) {
55
+ let total = 0;
56
+ for (const b of list) total += b.length;
57
+ const out = new Uint8Array(total);
58
+ let off = 0;
59
+ for (const b of list) { out.set(b, off); off += b.length; }
60
+ return out;
61
+ }
62
+
63
+ /** 用 latin1 解码一段字节(用于比较 ASCII 魔数,不受 UTF-8 影响) */
64
+ function latin1(u8, from, to) {
65
+ let s = '';
66
+ const end = to === undefined ? u8.length : Math.min(to, u8.length);
67
+ for (let i = from; i < end; i++) s += String.fromCharCode(u8[i]);
68
+ return s;
69
+ }
70
+
71
+ /**
72
+ * 字节读取器。
73
+ * @param {ArrayBuffer|Uint8Array} buf 数据
74
+ * @param {object} [opts]
75
+ * pos 起始位置(相对 buf)
76
+ * baseOffset 把「相对 buf 的偏移」换算成「相对整个文件的偏移」(缓冲区是切片时用)
77
+ * endian '>' 大端 / '<' 小端(默认 '<')。
78
+ * 注意:**同一个文件里可能两种字节序都有** —— UnityFS 容器头与 blocksInfo 表是
79
+ * 大端,而容器里内嵌的 SerializedFile 的字节序由它自己的头字节决定(通常小端)。
80
+ * 所以字节序是「读取器实例」的属性,不写成全局常量。
81
+ */
82
+ class Reader {
83
+ constructor(buf, opts) {
84
+ const o = opts || {};
85
+ this.raw = buf instanceof Uint8Array ? buf : new Uint8Array(buf);
86
+ this.view = new DataView(this.raw.buffer, this.raw.byteOffset, this.raw.byteLength);
87
+ this.pos = o.pos || 0;
88
+ this.baseOffset = o.baseOffset || 0;
89
+ this.le = o.endian !== '>';
90
+ this.length = this.raw.byteLength;
91
+ }
92
+
93
+ /** 相对整个文件的绝对偏移 */
94
+ get absOffset() { return this.baseOffset + this.pos; }
95
+ get remaining() { return this.length - this.pos; }
96
+ eof() { return this.pos >= this.length; }
97
+
98
+ need(n, what) {
99
+ if (this.pos + n > this.length) {
100
+ throw NS.errors.fail('ULB_ERR_CONTAINER_PARSE', `读取越界:需要 ${n} 字节(${what || '未命名字段'}),剩余 ${this.remaining}`);
101
+ }
102
+ }
103
+
104
+ seek(pos) { this.pos = pos; return this; }
105
+ skip(n) { this.pos += n; return this; }
106
+ align(n) { const r = this.pos % n; if (r !== 0) this.pos += n - r; return this; }
107
+
108
+ u8() { this.need(1, 'u8'); return this.view.getUint8(this.pos++); }
109
+ i8() { this.need(1, 'i8'); return this.view.getInt8(this.pos++); }
110
+ bool() { return this.u8() !== 0; }
111
+ u16() { this.need(2, 'u16'); const v = this.view.getUint16(this.pos, this.le); this.pos += 2; return v; }
112
+ i16() { this.need(2, 'i16'); const v = this.view.getInt16(this.pos, this.le); this.pos += 2; return v; }
113
+ u32() { this.need(4, 'u32'); const v = this.view.getUint32(this.pos, this.le); this.pos += 4; return v; }
114
+ i32() { this.need(4, 'i32'); const v = this.view.getInt32(this.pos, this.le); this.pos += 4; return v; }
115
+ f32() { this.need(4, 'f32'); const v = this.view.getFloat32(this.pos, this.le); this.pos += 4; return v; }
116
+ f64() { this.need(8, 'f64'); const v = this.view.getFloat64(this.pos, this.le); this.pos += 8; return v; }
117
+
118
+ /** 64 位整数(返回 Number;超出安全整数范围抛错,避免静默丢精度) */
119
+ i64(what) {
120
+ this.need(8, 'i64');
121
+ const v = this.view.getBigInt64(this.pos, this.le);
122
+ this.pos += 8;
123
+ const n = Number(v);
124
+ if (Math.abs(n) > Number.MAX_SAFE_INTEGER) {
125
+ throw NS.errors.fail('ULB_ERR_CONTAINER_PARSE', `64 位整数超出安全范围(${what || ''}):${v.toString()},本插件按 Number 处理会丢精度`);
126
+ }
127
+ return n;
128
+ }
129
+
130
+ /** 64 位整数(返回 BIGINT,不做范围检查;适合 pathID 这类会超过 2^53 的标识) */
131
+ i64b(what) {
132
+ this.need(8, 'i64');
133
+ const v = this.view.getBigInt64(this.pos, this.le);
134
+ this.pos += 8;
135
+ void what;
136
+ return v;
137
+ }
138
+
139
+ u64(what) { return this.i64(what); }
140
+
141
+ bytes(n, what) {
142
+ this.need(n, what || 'bytes');
143
+ const out = this.raw.subarray(this.pos, this.pos + n);
144
+ this.pos += n;
145
+ return out;
146
+ }
147
+
148
+ /** 以 NUL 结尾的字符串(Unity 的 string-to-null,UTF-8 解码) */
149
+ cstring(what) {
150
+ const start = this.pos;
151
+ while (this.pos < this.length && this.raw[this.pos] !== 0) this.pos++;
152
+ if (this.pos >= this.length) throw NS.errors.fail('ULB_ERR_CONTAINER_PARSE', `字符串缺少结尾 NUL(${what || ''})`);
153
+ const raw = this.raw.subarray(start, this.pos);
154
+ this.pos++; // 跳过 NUL
155
+ return new TextDecoder('utf-8').decode(raw);
156
+ }
157
+
158
+ /** Unity 的长度前缀字符串:i32 长度 + UTF-8 字节 + 4 字节对齐 */
159
+ string(what) {
160
+ const len = this.i32();
161
+ if (len === 0) { this.align(4); return ''; }
162
+ if (len < 0 || len > this.remaining) throw NS.errors.fail('ULB_ERR_CONTAINER_PARSE', `字符串长度非法(${what || ''}):${len}`);
163
+ const raw = this.bytes(len, what);
164
+ this.align(4);
165
+ return new TextDecoder('utf-8').decode(raw);
166
+ }
167
+ }
168
+
169
+ /**
170
+ * 可注入的 sha256 实现:Node 自检脚本启动时调用 setSha256() 注入 node:crypto 版本;
171
+ * 浏览器里若存在 crypto.subtle 则用内置实现;都没有时返回 null。
172
+ */
173
+ let sha256Impl = null;
174
+ function setSha256(fn) { sha256Impl = fn; }
175
+
176
+ async function sha256Hex(u8) {
177
+ if (sha256Impl) return sha256Impl(u8);
178
+ const subtle = root.crypto && root.crypto.subtle;
179
+ if (subtle && subtle.digest) {
180
+ const buf = u8.byteOffset === 0 && u8.byteLength === u8.buffer.byteLength
181
+ ? u8.buffer : u8.slice().buffer;
182
+ const d = await subtle.digest('SHA-256', buf);
183
+ return toHex(new Uint8Array(d));
184
+ }
185
+ return null;
186
+ }
187
+
188
+ NS.bytes = { Reader, toHex, concatBytes, latin1, sha256Hex, setSha256, crc32 };
189
+ }
@@ -0,0 +1,46 @@
1
+ // ============================================================================
2
+ // plugins/unity-live2d-bundle/lib/common-strings.js —— Unity 类型树"公共字符串表"
3
+ //
4
+ // 用途:类型树节点里的字段名/类型名有两种存法 ——
5
+ // ① 最高位为 0:偏移 → 指向该类型树自带的字符串池;
6
+ // ② 最高位为 1:下标 → 指向 Unity 内置的这张公共表(跨文件共享的常用名字,省字节)。
7
+ // 没有这张表就解不出 ② 的名字(本样本的 Texture2D/MonoBehaviour 类型树就用到了它)。
8
+ //
9
+ // 数据来源:Unity 的 CommonString 表(随类型树 TPK 数据分发),
10
+ // 本文件是它的**离线快照**,键=下标、值=字符串;仅用于解析 ②,不参与任何游戏特有逻辑。
11
+ // ============================================================================
12
+
13
+ 'use strict';
14
+
15
+ (function (root) {
16
+ const NS = (root.__ULB__ = root.__ULB__ || {});
17
+ NS.commonStrings = {
18
+ 0: 'AABB', 5: 'AnimationClip', 19: 'AnimationCurve', 34: 'AnimationState', 49: 'Array',
19
+ 55: 'Base', 60: 'BitField', 69: 'bitset', 76: 'bool', 81: 'char', 86: 'ColorRGBA',
20
+ 96: 'Component', 106: 'data', 111: 'deque', 117: 'double', 124: 'dynamic_array',
21
+ 138: 'FastPropertyName', 155: 'first', 161: 'float', 167: 'Font', 172: 'GameObject',
22
+ 183: 'Generic Mono', 196: 'GradientNEW', 208: 'GUID', 213: 'GUIStyle', 222: 'int',
23
+ 226: 'list', 231: 'long long', 241: 'map', 245: 'Matrix4x4f', 256: 'MdFour',
24
+ 263: 'MonoBehaviour', 277: 'MonoScript', 288: 'm_ByteSize', 299: 'm_Curve',
25
+ 307: 'm_EditorClassIdentifier', 331: 'm_EditorHideFlags', 349: 'm_Enabled',
26
+ 359: 'm_ExtensionPtr', 374: 'm_GameObject', 387: 'm_Index', 395: 'm_IsArray',
27
+ 405: 'm_IsStatic', 416: 'm_MetaFlag', 427: 'm_Name', 434: 'm_ObjectHideFlags',
28
+ 452: 'm_PrefabInternal', 469: 'm_PrefabParentObject', 490: 'm_Script',
29
+ 499: 'm_StaticEditorFlags', 519: 'm_Type', 526: 'm_Version', 536: 'Object', 543: 'pair',
30
+ 548: 'PPtr<Component>', 564: 'PPtr<GameObject>', 581: 'PPtr<Material>',
31
+ 596: 'PPtr<MonoBehaviour>', 616: 'PPtr<MonoScript>', 633: 'PPtr<Object>',
32
+ 646: 'PPtr<Prefab>', 659: 'PPtr<Sprite>', 672: 'PPtr<TextAsset>', 688: 'PPtr<Texture>',
33
+ 702: 'PPtr<Texture2D>', 718: 'PPtr<Transform>', 734: 'Prefab', 741: 'Quaternionf',
34
+ 753: 'Rectf', 759: 'RectInt', 767: 'RectOffset', 778: 'second', 785: 'set', 789: 'short',
35
+ 795: 'size', 800: 'SInt16', 807: 'SInt32', 814: 'SInt64', 821: 'SInt8', 827: 'staticvector',
36
+ 840: 'string', 847: 'TextAsset', 857: 'TextMesh', 866: 'Texture', 874: 'Texture2D',
37
+ 884: 'Transform', 894: 'TypelessData', 907: 'UInt16', 914: 'UInt32', 921: 'UInt64',
38
+ 928: 'UInt8', 934: 'unsigned int', 947: 'unsigned long long', 966: 'unsigned short',
39
+ 981: 'vector', 988: 'Vector2f', 997: 'Vector3f', 1006: 'Vector4f',
40
+ 1015: 'm_ScriptingClassIdentifier', 1042: 'Gradient', 1051: 'Type*', 1057: 'int2_storage',
41
+ 1070: 'int3_storage', 1083: 'BoundsInt', 1093: 'm_CorrespondingSourceObject',
42
+ 1121: 'm_PrefabInstance', 1138: 'm_PrefabAsset', 1152: 'FileSize', 1161: 'Hash128',
43
+ 1169: 'RenderingLayerMask', 1188: 'fixed_array', 1200: 'EntityId',
44
+ 1209: 'LoadableObjectId', 1226: 'LoadableSceneId',
45
+ };
46
+ })(typeof globalThis !== 'undefined' ? globalThis : this);
@@ -0,0 +1,197 @@
1
+ // ============================================================================
2
+ // lib/dxt.js —— BC/DXT 家族纹理解码(BC1/DXT1、BC3/DXT5、BC4、BC5)
3
+ //
4
+ // 为什么需要:Unity 的 PC/主机资源包常用 BC 系列(Unity TextureFormat 10=DXT1、12=DXT5、
5
+ // 26=BC4、27=BC5),而移动端资源包用 ETC2。两类资源包都可能出现在同一批素材里,
6
+ // 缺哪一种都会让"整个模型不可用"(纹理解不出来 → 舞台拿不到贴图)。
7
+ //
8
+ // 挂载:globalThis.__ULB__.dxt = { decodeBc1, decodeBc3, decodeBc4, decodeBc5 }
9
+ //
10
+ // 实现要点(都是块式压缩,逐 4×4 块解):
11
+ // · BC1:每块 8 字节 = 两个 RGB565 端点 + 32 位 2bit 索引;c0>c1 为 4 色模式,
12
+ // 否则 3 色 + 透明(用于 1bit alpha)。
13
+ // · BC3:每块 16 字节 = 8 字节 alpha 块(a0/a1 + 48 位 3bit 索引)+ 8 字节颜色块(同 BC1 的 4 色模式)。
14
+ // · BC4:单通道,就是 BC3 的 alpha 块(8 字节)。
15
+ // · BC5:双通道,两个 BC4 alpha 块(16 字节)→ R/G,B 置 0、A 置 255。
16
+ // · 所有解码都按行优先输出 RGBA,边缘块不足 4×4 时只写落在图内的像素。
17
+ // ============================================================================
18
+
19
+ 'use strict';
20
+
21
+ {
22
+ /** 5:6:5 → 8:8:8(按位扩展,与 GPU 的端点插值一致:复制高位) */
23
+ function r5g6b5(v) {
24
+ const r = (v >> 11) & 0x1f;
25
+ const g = (v >> 5) & 0x3f;
26
+ const b = v & 0x1f;
27
+ return [(r << 3) | (r >> 2), (g << 2) | (g >> 4), (b << 3) | (b >> 2)];
28
+ }
29
+
30
+ function u16(d, o) { return d[o] | (d[o + 1] << 8); }
31
+
32
+ /**
33
+ * 解一个 BC1 颜色块(8 字节)到 4×4 的 RGBA 输出。
34
+ * @param {Uint8Array} d 压缩数据
35
+ * @param {number} o 块起始偏移
36
+ * @param {boolean} fourColorOnly true 时强制 4 色模式(BC3 的颜色块用)
37
+ * @returns {{colors:number[][], idx:number[]}} colors 为 4 个 [r,g,b,a]
38
+ */
39
+ function readColorBlock(d, o, fourColorOnly) {
40
+ const c0 = u16(d, o);
41
+ const c1 = u16(d, o + 2);
42
+ const p0 = r5g6b5(c0);
43
+ const p1 = r5g6b5(c1);
44
+ let colors;
45
+ if (fourColorOnly || c0 > c1) {
46
+ // 4 色模式:p2 = (2*p0 + p1)/3,p3 = (p0 + 2*p1)/3
47
+ colors = [
48
+ [p0[0], p0[1], p0[2], 255],
49
+ [p1[0], p1[1], p1[2], 255],
50
+ [(2 * p0[0] + p1[0]) / 3 | 0, (2 * p0[1] + p1[1]) / 3 | 0, (2 * p0[2] + p1[2]) / 3 | 0, 255],
51
+ [(p0[0] + 2 * p1[0]) / 3 | 0, (p0[1] + 2 * p1[1]) / 3 | 0, (p0[2] + 2 * p1[2]) / 3 | 0, 255],
52
+ ];
53
+ } else {
54
+ // 3 色 + 透明模式:p2 = (p0+p1)/2,p3 = 全透明
55
+ colors = [
56
+ [p0[0], p0[1], p0[2], 255],
57
+ [p1[0], p1[1], p1[2], 255],
58
+ [(p0[0] + p1[0]) / 2 | 0, (p0[1] + p1[1]) / 2 | 0, (p0[2] + p1[2]) / 2 | 0, 255],
59
+ [0, 0, 0, 0],
60
+ ];
61
+ }
62
+ const bits = d[o + 4] | (d[o + 5] << 8) | (d[o + 6] << 16) | (d[o + 7] << 24);
63
+ const idx = new Array(16);
64
+ for (let i = 0; i < 16; i++) idx[i] = (bits >>> (i * 2)) & 0x3;
65
+ return { colors, idx };
66
+ }
67
+
68
+ /**
69
+ * 解一个 alpha 块(8 字节)到 16 个 0~255 的 alpha 值(BC3/BC4 共用)。
70
+ * a0 > a1:8 档线性插值;a0 <= a1:6 档插值 + 0 与 255 两个极值。
71
+ */
72
+ function readAlphaBlock(d, o) {
73
+ const a0 = d[o];
74
+ const a1 = d[o + 1];
75
+ const table = new Array(8);
76
+ table[0] = a0;
77
+ table[1] = a1;
78
+ if (a0 > a1) {
79
+ for (let i = 1; i <= 6; i++) table[i + 1] = ((7 - i) * a0 + i * a1) / 7 | 0;
80
+ } else {
81
+ for (let i = 1; i <= 4; i++) table[i + 1] = ((5 - i) * a0 + i * a1) / 5 | 0;
82
+ table[6] = 0;
83
+ table[7] = 255;
84
+ }
85
+ // 48 位、每像素 3bit 的索引(跨 6 字节)
86
+ const out = new Array(16);
87
+ let acc = 0;
88
+ let bits = 0;
89
+ let p = o + 2;
90
+ for (let i = 0; i < 16; i++) {
91
+ while (bits < 3) { acc |= d[p++] << bits; bits += 8; }
92
+ out[i] = table[acc & 7];
93
+ acc >>>= 3;
94
+ bits -= 3;
95
+ }
96
+ return out;
97
+ }
98
+
99
+ /** 把 4×4 块的像素写进 RGBA 输出(自动裁剪到图内) */
100
+ function writeBlock(out, width, height, bx, by, pixels) {
101
+ for (let y = 0; y < 4; y++) {
102
+ const py = by * 4 + y;
103
+ if (py >= height) break;
104
+ for (let x = 0; x < 4; x++) {
105
+ const px = bx * 4 + x;
106
+ if (px >= width) break;
107
+ const p = pixels[y * 4 + x];
108
+ const o = (py * width + px) * 4;
109
+ out[o] = p[0];
110
+ out[o + 1] = p[1];
111
+ out[o + 2] = p[2];
112
+ out[o + 3] = p[3];
113
+ }
114
+ }
115
+ }
116
+
117
+ /** 解 DXT1/BC1(每块 8 字节) */
118
+ function decodeBc1(data, width, height) {
119
+ const bw = Math.ceil(width / 4);
120
+ const bh = Math.ceil(height / 4);
121
+ const need = bw * bh * 8;
122
+ if (data.length < need) throw NS.errors.fail('ULB_ERR_TEX_DATA_SHORT', `DXT1 数据不足:需要 ${need} 字节,实际 ${data.length}`);
123
+ const out = new Uint8Array(width * height * 4);
124
+ for (let by = 0; by < bh; by++) {
125
+ for (let bx = 0; bx < bw; bx++) {
126
+ const { colors, idx } = readColorBlock(data, (by * bw + bx) * 8, false);
127
+ const pixels = new Array(16);
128
+ for (let i = 0; i < 16; i++) pixels[i] = colors[idx[i]];
129
+ writeBlock(out, width, height, bx, by, pixels);
130
+ }
131
+ }
132
+ return out;
133
+ }
134
+
135
+ /** 解 DXT5/BC3(每块 16 字节 = alpha 块 + 颜色块) */
136
+ function decodeBc3(data, width, height) {
137
+ const bw = Math.ceil(width / 4);
138
+ const bh = Math.ceil(height / 4);
139
+ const need = bw * bh * 16;
140
+ if (data.length < need) throw NS.errors.fail('ULB_ERR_TEX_DATA_SHORT', `DXT5 数据不足:需要 ${need} 字节,实际 ${data.length}`);
141
+ const out = new Uint8Array(width * height * 4);
142
+ for (let by = 0; by < bh; by++) {
143
+ for (let bx = 0; bx < bw; bx++) {
144
+ const o = (by * bw + bx) * 16;
145
+ const alphas = readAlphaBlock(data, o);
146
+ const { colors, idx } = readColorBlock(data, o + 8, true);
147
+ const pixels = new Array(16);
148
+ for (let i = 0; i < 16; i++) {
149
+ const c = colors[idx[i]];
150
+ pixels[i] = [c[0], c[1], c[2], alphas[i]];
151
+ }
152
+ writeBlock(out, width, height, bx, by, pixels);
153
+ }
154
+ }
155
+ return out;
156
+ }
157
+
158
+ /** 解 BC4(单通道,每块 8 字节):R=通道值,G/B=0,A=255 */
159
+ function decodeBc4(data, width, height) {
160
+ const bw = Math.ceil(width / 4);
161
+ const bh = Math.ceil(height / 4);
162
+ const need = bw * bh * 8;
163
+ if (data.length < need) throw NS.errors.fail('ULB_ERR_TEX_DATA_SHORT', `BC4 数据不足:需要 ${need} 字节,实际 ${data.length}`);
164
+ const out = new Uint8Array(width * height * 4);
165
+ for (let by = 0; by < bh; by++) {
166
+ for (let bx = 0; bx < bw; bx++) {
167
+ const vals = readAlphaBlock(data, (by * bw + bx) * 8);
168
+ const pixels = vals.map((v) => [v, 0, 0, 255]);
169
+ writeBlock(out, width, height, bx, by, pixels);
170
+ }
171
+ }
172
+ return out;
173
+ }
174
+
175
+ /** 解 BC5(双通道,每块 16 字节 = 两个 BC4 块):R/G=两通道,B=0,A=255 */
176
+ function decodeBc5(data, width, height) {
177
+ const bw = Math.ceil(width / 4);
178
+ const bh = Math.ceil(height / 4);
179
+ const need = bw * bh * 16;
180
+ if (data.length < need) throw NS.errors.fail('ULB_ERR_TEX_DATA_SHORT', `BC5 数据不足:需要 ${need} 字节,实际 ${data.length}`);
181
+ const out = new Uint8Array(width * height * 4);
182
+ for (let by = 0; by < bh; by++) {
183
+ for (let bx = 0; bx < bw; bx++) {
184
+ const o = (by * bw + bx) * 16;
185
+ const r = readAlphaBlock(data, o);
186
+ const g = readAlphaBlock(data, o + 8);
187
+ const pixels = new Array(16);
188
+ for (let i = 0; i < 16; i++) pixels[i] = [r[i], g[i], 0, 255];
189
+ writeBlock(out, width, height, bx, by, pixels);
190
+ }
191
+ }
192
+ return out;
193
+ }
194
+
195
+ const NS = (globalThis.__ULB__ = globalThis.__ULB__ || {});
196
+ NS.dxt = { decodeBc1, decodeBc3, decodeBc4, decodeBc5 };
197
+ }
@@ -0,0 +1,71 @@
1
+ // ============================================================================
2
+ // lib/errors.js —— 插件错误码表 + 带码的失败构造器
3
+ //
4
+ // 为什么需要:只给中文 message 时,调用方(新前端/其它程序)无法**程序化区分**失败类型——
5
+ // 做重试、降级、提示都只能靠字符串匹配(脆、且随文案变化而失效)。
6
+ // 这里给每类失败一个**稳定错误码**(大写蛇形 + ULB_ERR_ 前缀),message 仍保留中文可读说明。
7
+ //
8
+ // 稳定性约定:
9
+ // · 码按「失败类别」定义,**不按行号/临时条件生成**;同一失败原因永远同一码。
10
+ // · 已发布的码不删不改(需要区分新情况时**新增**码)。
11
+ // · 错误对象上:err.code(稳定码)+ err.message(中文可读)+ err.ulb = true(便于跨层识别)。
12
+ //
13
+ // 挂载:globalThis.__ULB__.errors = { CODES, fail, isUlbError, codeOf }
14
+ // ============================================================================
15
+
16
+ 'use strict';
17
+
18
+ {
19
+ /** 稳定错误码表(值即码本身;键用于文档与自检遍历) */
20
+ const CODES = {
21
+ BAD_ARGS: 'ULB_ERR_BAD_ARGS', // 调用参数缺失/非法(缺 rootId/rel 等)
22
+ IO: 'ULB_ERR_IO', // 读取资源失败(宿主取文件失败、HTTP 非 2xx、超时)
23
+ NO_FILE: 'ULB_ERR_NO_FILE', // 目标文件不存在/为空(路径对但文件没有)
24
+ NOT_UNITYFS: 'ULB_ERR_NOT_UNITYFS', // 文件不是 UnityFS 容器
25
+ NO_CAB: 'ULB_ERR_NO_CAB', // 容器里没有 CAB-* 节点(不是资产包)
26
+ CONTAINER_PARSE: 'ULB_ERR_CONTAINER_PARSE', // 容器/序列化/类型树解析失败(数据布局不符该版本)
27
+ LZMA_FAIL: 'ULB_ERR_LZMA_FAIL', // LZMA 解压失败(数据损坏 / 解出长度与声明不符)
28
+ LZMA_UNAVAILABLE: 'ULB_ERR_LZMA_UNAVAILABLE', // LZMA 解码器未加载(lib/lzma-d-min.js 未按序声明)
29
+ EXTRACT: 'ULB_ERR_EXTRACT', // 从对象表抽取资产失败(缺 .resS、越界等)
30
+ TEXTURE_FORMAT_UNSUPPORTED: 'ULB_ERR_TEX_FORMAT_UNSUPPORTED', // 纹理格式未实现
31
+ TEXTURE_DATA_SHORT: 'ULB_ERR_TEX_DATA_SHORT', // 纹理压缩数据不足(截断/尺寸不符)
32
+ TEXTURE_DECODE: 'ULB_ERR_TEX_DECODE', // 纹理解码失败(其余原因)
33
+ CURVE_BINDING_MISMATCH: 'ULB_ERR_CURVE_BINDING_MISMATCH', // 曲线数与绑定数不一致
34
+ STREAMED_CLIP_INVALID: 'ULB_ERR_STREAMED_CLIP_INVALID', // StreamedClip 结构异常
35
+ MODEL_BUILD: 'ULB_ERR_MODEL_BUILD', // 拼装可渲染模型失败(缺 moc3/贴图等)
36
+ NO_HOST: 'ULB_ERR_NO_HOST', // 宿主能力面缺失(§3.6:fetchFile 不可用且 file.bytes 缺失,可退化)
37
+ EXPORT_NO_SPACE: 'ULB_ERR_EXPORT_NO_SPACE', // 导出:磁盘剩余不足(预估 ×1.5 仍不够)
38
+ EXPORT_INTERRUPTED: 'ULB_ERR_EXPORT_INTERRUPTED', // 导出:被 SIGINT/SIGTERM 中断(临时目录已清理)
39
+ };
40
+
41
+ /**
42
+ * 构造一个带稳定错误码的 Error。
43
+ * @param {string} code CODES 里的码
44
+ * @param {string} message 中文可读说明
45
+ * @param {object} [extra] 附加字段(会挂到 err 上,便于调用方取上下文,如 { texture: 'texture_00' })
46
+ */
47
+ function fail(code, message, extra) {
48
+ const err = new Error(message);
49
+ err.code = code;
50
+ err.ulb = true;
51
+ if (extra && typeof extra === 'object') {
52
+ for (const k of Object.keys(extra)) {
53
+ if (k !== 'code' && k !== 'message' && k !== 'ulb') err[k] = extra[k];
54
+ }
55
+ }
56
+ return err;
57
+ }
58
+
59
+ /** 是否本插件产出的带码错误 */
60
+ function isUlbError(e) {
61
+ return Boolean(e && e.ulb === true && typeof e.code === 'string');
62
+ }
63
+
64
+ /** 取错误码(非本插件的错误返回 null,便于调用方区分) */
65
+ function codeOf(e) {
66
+ return isUlbError(e) ? e.code : null;
67
+ }
68
+
69
+ const NS = (globalThis.__ULB__ = globalThis.__ULB__ || {});
70
+ NS.errors = { CODES, fail, isUlbError, codeOf };
71
+ }