# 17 — 自动生成的 id 改成自增 Status: resolved Type: task ## 需求 > 自动生成的 json 相关的 id 采取自增的形式,如 audios 两处(用户确认「两者都要」): | | 旧 | 新 | | --- | --- | --- | | `project.json` 属性的 `index` / `order` | 手写在 `src/project.template.json` | build 按属性表书写顺序自动编号 | | 音源 id(`meta.json` 的 `audio.choices[].id`) | 手写字符串(`zaiduheni` / `xilian` / `pv37`) | build 自增分配(`"1"` / `"2"` / `"3"`) | ## ① index / order 以前每个属性都要写 `"index": 4, "order": 104`。代价在**加一个属性**时才显出来: 后面全部要重编号——上一轮加 `use_custom_audio` 手改了 6 处,而且在产物 diff 里 刷出 8 行纯噪音,把真正的改动淹掉了。 现在 `numberProperties()` 按属性表的书写顺序编号: ``` index = 0,1,2… order = 100+index ``` **必须在删属性之后编号**:单档分发会删掉 `preset`/`preset_note`/`bgm`/`bgm_note` 四行, 以前删完就留下空号(0,1,4,5,6,7,8)。现在自动补上,单档是 0…6 连续。 `schemecolor` 是唯一例外:它是 WE 的**内置**属性,线上就是 `order 0` 且**没有** `index`。 用 `"$order": 0` 显式钉住,钉住的属性不参与 index 序列——这样 `collection-all` 的产物 与线上逐字一致,diff 里只剩真实改动。 ## ② 音源 id `meta.json` 里不再写 id: ```json "audio": { "choices": [ { "name": "「再度和你」", "file": "audios/zaiduheni.flac" }, { "name": "昔涟", "file": "audios/xilian-src.flac" } ] } ``` ### 一个必须解决的约束:id 要**全项目**唯一 第一版我按「每档壁纸各从 1 开始」写,**这是错的**。`generate.ts` 里: ```ts bgmOptions.push({ label: choice.name, value: choice.id }); ``` `bgm` 下拉会把一个分发里**所有**壁纸的音源平铺进同一个 combo。两档壁纸都叫 `"1"` 的话, 选中的到底是哪一个就无从分辨了。 所以用一个**全项目计数器**,分配顺序固定为: ``` 游戏 → 该游戏的共享音频 → 各壁纸的音源(按 id 排序) ``` 遍历的是**整棵资源库**而不是本次要构建的分发子集——否则同一个音源在不同分发里会拿到不同的 id,用户从合集切到单档时 bgm 选择就失效了。实测:xilian 的两个音源在 `collection-all` 与 `single-hsr-xilian` 里都是 `"2"` / `"3"`。 `default` 也跟着改:从「id 字符串」变成「**1 起的位置**」,省略 = 第一个。换算成 0 起的 `defaultIndex` 只做一处(`vault.ts` 的 `readAudioDecl`)。 ### 代价(用户已确认接受) 音源 id 会进 `project.json` 的 `bgm` combo value。改成数字后,**老用户已保存的 bgm 选择会失效** (和壁纸预设 id 同一个问题)。运行时对这种情况是安全的:`bgmSource()` 找不到匹配就回落到 本壁纸默认音源。另外在音源清单中间插入一条会让后面的 id 整体后移——加音源请往后加。 ## 顺手修掉一个「一直红着」的测试 改完跑 `test-props.mjs`,2 项失败: ``` ✗ bgm 选「昔涟」后填自定义 URL → 期望 custom-track.mp3,实得 xilian-src.flac ✗ 切壁纸不得清掉自定义 URL → 期望 custom-track.mp3,实得 pv37.mp3 ``` **这不是这次改动造成的**:上一轮加 `use_custom_audio` 时,`audio_file` 被改成只在开关打开时 才生效,而当时我**没有重跑这个测试**——它从那时起就一直是红的。`test-acceptance.mjs` 同理。 两处都补上开关,并顺手把「开关关着时填 URL 不生效」加成一条断言——那正是这个开关的核心语义。 > 改了语义却没跑对应的测试,等于没测。这次是靠改另一个东西时才撞出来的。 ## 验证 全量回归,全绿: - `pnpm check`:四个分发、`check:dist` / `check:syntax` / `check:paths`("3 条音源声明无孤儿文件") - `test-props.mjs`(bgm 选择/回落、fps 限流)、`test-resize.mjs`、`test-acceptance.mjs`、`verify-fitter.mjs` - 调试服冒烟、浏览器冒烟、面板还原度(10 组)、热更新 - 四档自包含包 `file://`、静态托管预览、sim 门禁、内联守卫、模块改写 - `verify-visual-equivalence`:6 组与重构前逐像素相同 - `diff-project`:差异 13 → **14**,新增的那一条是 `bgm.options`(value 从名字变数字), 正是本次有意的改动;`index`/`order` 相关**没有**新增差异