Files
SpineWallpaper/dist/scripts/index.js
T
Shuery 4662856963 fix: 初始化竞态、用户级覆盖语义与死代码(重构四个控制器)
初始化竞态(已实证):旧 changeConfig() 整个函数体都在 if (this.player) 里,含配置赋值,
WE 在 window.load 之前下发属性时被静默丢弃,导致背景/音乐已切到新壁纸、立绘还是旧的。
改为「状态先写、应用后置」:index.js 用单一 state 记录(presetId/audioSource/audioVolume),
render() 决定能否立刻应用;setConfig() 无条件记录配置,create() 用记下的配置创建。

- 删除 index.js 里重复的 wallpaperRegisterListener(该 API 在本机 WE 不存在)
- 删除 adjustCanvas():播放器每帧自己做 renderer.resize(1) 且已注册 resize 监听,
  而它用 getBoundingClientRect() 写 canvas.width 却不乘 DPR,属于有害的重复实现
- 用户级音源/音量覆盖:切壁纸不再清回预设默认值(旧 PresetController 的启发式已移除)
- 同源设置改为 no-op:否则两档壁纸共用同一首曲子时一切换就从头播放
- 只在壁纸真的变了才重建播放器,否则拖动音量滑块会触发重新下载 3.6MB 骨架+贴图
- 未知 preset id 保持现状并告警,不再静默回退

验证:属性在 DOMContentLoaded 下发时玩家动画正确为 animation(kv37);
用户自定义音源 custom-track.mp3 与音量 0.2 在切壁纸后完整保留;
重发同一预设时音乐从 1.3s 连续到 1.9s 未重启;未知 id 不崩。
对拍:与重构前同强冻结设置 8 批次 6 配置逐像素完全相同(差异 0)。
2026-09-19 19:53:15 +08:00

87 lines
3.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Presets from "./presets.js";
import PresetController from "./preset-controller.js";
import BackgroundController from "./background-controller.js";
import SpineController from "./spine-controller.js";
import AudioController from "./audio-controller.js";
// 与 project.json 里属性的默认值保持一致
const DEFAULT_PRESET_ID = "xilian";
const DEFAULT_VOLUME = 0.5;
const presets = new PresetController(Presets);
const backgroundController = new BackgroundController();
const spineController = new SpineController("spine-container");
const audioController = new AudioController("background-music");
// 唯一的真相来源。WE 可能在 window.load 之前就下发用户属性,所以这里只记录状态;
// 渲染时再决定"能不能立刻应用"——只有播放器需要等到 load 之后才存在。
const state = {
ready: false,
presetId: "",
audioSource: "", // 空字符串 = 用当前预设的默认音源
audioVolume: DEFAULT_VOLUME,
};
let appliedPresetId = "";
function render() {
const presetId = state.presetId || DEFAULT_PRESET_ID;
const preset = presets.get(presetId);
if (!preset) return;
// 只有壁纸真的换了才碰背景与骨架。否则拖动音量滑块都会重建播放器
// (重建 = 重新下载 3.4 MB 骨架与全部贴图)。
if (appliedPresetId !== presetId) {
appliedPresetId = presetId;
backgroundController.setImage(preset.backgroundImage);
spineController.setConfig(preset.spineConfig); // 播放器还不存在时只是记下来
}
// 用户自定义音源优先;用户没给就用当前壁纸的默认音源
audioController.setSource(state.audioSource || preset.audioOptions.source);
audioController.setVolume(state.audioVolume);
if (state.ready) audioController.play();
}
window.addEventListener("load", function () {
state.ready = true;
render(); // 先把状态落到各控制器(此时播放器尚不存在,只写配置)
spineController.create(); // 再用写好的配置创建播放器
});
// 必须在模块顶层注册:属性事件可能在 window.load 之前到达
window.wallpaperPropertyListener = {
applyUserProperties: function (properties) {
// 先写状态:无条件记录,与播放器是否存在、是否加载完成无关
if (properties.preset) {
const presetId = properties.preset.value;
if (presets.has(presetId)) {
state.presetId = presetId;
} else if (presetId) {
console.warn(`忽略未知的预设 id:${presetId}`);
}
}
if (properties.audio_file) {
state.audioSource = String(properties.audio_file.value || "").trim();
}
if (properties.audio_volume) {
const volume = Number(properties.audio_volume.value);
if (Number.isFinite(volume)) {
state.audioVolume = Math.max(0, Math.min(1, volume));
}
}
render();
},
applyGeneralProperties: function (properties) {
if (properties.fps) {
// fps 限制在第 05 步接入:WE 不替壁纸限流,需要自己按 properties.fps 节流绘制
}
},
};