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)。
This commit is contained in:
1 parent
a391021041
commit
4662856963
8 files changed
+1209
-240
No files matched your search
Vendored
+86
-87
@@ -1,87 +1,86 @@
|
||||
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";
|
||||
|
||||
let presetController = new PresetController(Presets);
|
||||
|
||||
let { backgroundImage, spineConfig, audioOptions } =
|
||||
presetController.set("xilian");
|
||||
|
||||
let backgroundController = new BackgroundController(backgroundImage);
|
||||
let spineController = new SpineController("spine-container", spineConfig);
|
||||
let audioController = new AudioController("background-music", audioOptions);
|
||||
|
||||
let currentAudioSource = "";
|
||||
let currentAudioVolume = 0;
|
||||
|
||||
window.addEventListener("load", function () {
|
||||
backgroundController.setImage();
|
||||
spineController.create();
|
||||
audioController.play();
|
||||
});
|
||||
|
||||
window.addEventListener("resize", () => {
|
||||
spineController.adjustCanvas();
|
||||
});
|
||||
|
||||
window.wallpaperRegisterListener = {
|
||||
applyGeneralProperties: function (properties) {
|
||||
if (properties.fps) {
|
||||
// wallpaperSettings.fps = properties.fps;
|
||||
}
|
||||
},
|
||||
applyUserProperties: function (properties) {
|
||||
if (properties.preset) {
|
||||
const preset = properties.preset.value;
|
||||
let { backgroundImage, spineConfig, audioOptions } =
|
||||
presetController.set(preset);
|
||||
backgroundController.changeImage(backgroundImage);
|
||||
spineController.changeConfig(spineConfig);
|
||||
audioController.changeOptions(audioOptions);
|
||||
}
|
||||
if (properties.audio_file) {
|
||||
const audio_file = properties.audio_file.value;
|
||||
currentAudioSource = audio_file;
|
||||
audioController.changeSource(audio_file);
|
||||
}
|
||||
if (properties.audio_volume) {
|
||||
const audio_volume = properties.audio_volume.value;
|
||||
currentAudioVolume = audio_volume;
|
||||
audioController.changeVolume(audio_volume);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
window.wallpaperPropertyListener = {
|
||||
applyGeneralProperties: function (properties) {
|
||||
if (properties.fps) {
|
||||
// wallpaperSettings.fps = properties.fps;
|
||||
}
|
||||
},
|
||||
applyUserProperties: function (properties) {
|
||||
if (properties.preset) {
|
||||
const preset = properties.preset.value;
|
||||
let { backgroundImage, spineConfig, audioOptions } = presetController.set(
|
||||
preset,
|
||||
currentAudioSource,
|
||||
currentAudioVolume
|
||||
);
|
||||
backgroundController.changeImage(backgroundImage);
|
||||
spineController.changeConfig(spineConfig);
|
||||
audioController.changeOptions(audioOptions);
|
||||
}
|
||||
if (properties.audio_file) {
|
||||
const audio_file = properties.audio_file.value;
|
||||
currentAudioSource = audio_file;
|
||||
audioController.changeSource(audio_file);
|
||||
}
|
||||
if (properties.audio_volume) {
|
||||
const audio_volume = properties.audio_volume.value;
|
||||
currentAudioVolume = audio_volume;
|
||||
audioController.changeVolume(audio_volume);
|
||||
}
|
||||
},
|
||||
};
|
||||
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 节流绘制
|
||||
}
|
||||
},
|
||||
};
|
||||
Reference in new issue
Block a user