Make map editor preload texture previews
This commit is contained in:
+60
-15
@@ -9,6 +9,7 @@ const state = {
|
||||
imagePreviews: new Map(),
|
||||
imageLoading: new Set(),
|
||||
imageFailures: new Set(),
|
||||
previewLoadToken: 0,
|
||||
history: [],
|
||||
dragging: null,
|
||||
};
|
||||
@@ -143,26 +144,63 @@ function loadImage(url) {
|
||||
});
|
||||
}
|
||||
|
||||
function preloadMapImages(map) {
|
||||
for (const layer of map.layers) {
|
||||
for (const rect of layer.rects) {
|
||||
if (rect.texture) queueImagePreview(rect.texture);
|
||||
async function preloadMapImages(map) {
|
||||
const textures = uniqueMapTextures(map);
|
||||
if (!textures.length) return;
|
||||
|
||||
const token = state.previewLoadToken + 1;
|
||||
state.previewLoadToken = token;
|
||||
setStatus(`正在加载贴图预览 0/${textures.length}`);
|
||||
|
||||
let loaded = 0;
|
||||
let failed = 0;
|
||||
await Promise.all(textures.map(async (texturePath) => {
|
||||
const ok = await queueImagePreview(texturePath, { refreshAfterLoad: false });
|
||||
if (ok) loaded += 1;
|
||||
else failed += 1;
|
||||
if (state.previewLoadToken === token) {
|
||||
setStatus(`正在加载贴图预览 ${loaded + failed}/${textures.length}`);
|
||||
}
|
||||
}));
|
||||
|
||||
if (state.previewLoadToken !== token) return;
|
||||
refresh();
|
||||
if (failed) {
|
||||
setStatus(`贴图预览完成:成功 ${loaded},失败 ${failed}`);
|
||||
} else {
|
||||
setStatus(`贴图预览完成:${loaded}/${textures.length}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function queueImagePreview(texturePath) {
|
||||
function uniqueMapTextures(map) {
|
||||
const textures = [];
|
||||
const seen = new Set();
|
||||
for (const layer of map.layers) {
|
||||
for (const rect of layer.rects) {
|
||||
if (!rect.texture || seen.has(rect.texture)) continue;
|
||||
seen.add(rect.texture);
|
||||
textures.push(rect.texture);
|
||||
}
|
||||
}
|
||||
return textures;
|
||||
}
|
||||
|
||||
async function queueImagePreview(texturePath, options = {}) {
|
||||
if (!texturePath ||
|
||||
state.imagePreviews.has(texturePath) ||
|
||||
state.imageLoading.has(texturePath) ||
|
||||
state.imageFailures.has(texturePath)) {
|
||||
return;
|
||||
state.imagePreviews.has(texturePath)) {
|
||||
return true;
|
||||
}
|
||||
if (state.imageLoading.has(texturePath)) {
|
||||
return false;
|
||||
}
|
||||
if (state.imageFailures.has(texturePath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const url = previewUrlForTexture(texturePath);
|
||||
if (!url) {
|
||||
state.imageFailures.add(texturePath);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
state.imageLoading.add(texturePath);
|
||||
@@ -170,10 +208,12 @@ async function queueImagePreview(texturePath) {
|
||||
const image = await loadImage(url);
|
||||
state.imagePreviews.set(texturePath, image);
|
||||
state.imageFailures.delete(texturePath);
|
||||
refresh();
|
||||
if (options.refreshAfterLoad !== false) refresh();
|
||||
return true;
|
||||
} catch (error) {
|
||||
state.imageFailures.add(texturePath);
|
||||
setStatus(`贴图预览加载失败:${texturePath}`);
|
||||
return false;
|
||||
} finally {
|
||||
state.imageLoading.delete(texturePath);
|
||||
}
|
||||
@@ -183,9 +223,14 @@ function previewUrlForTexture(texturePath) {
|
||||
const clean = String(texturePath || "").replace(/\\/g, "/").replace(/^\/+/, "");
|
||||
if (!clean) return "";
|
||||
if (/^(blob:|data:|https?:\/\/)/i.test(clean)) return clean;
|
||||
if (clean.startsWith("assets/")) return `../../game/${clean}`;
|
||||
if (clean.startsWith("game/assets/")) return `../../${clean}`;
|
||||
return clean;
|
||||
if (clean.startsWith("assets/")) return cacheBustedUrl(`${location.origin}/game/${clean}`);
|
||||
if (clean.startsWith("game/assets/")) return cacheBustedUrl(`${location.origin}/${clean}`);
|
||||
return cacheBustedUrl(clean);
|
||||
}
|
||||
|
||||
function cacheBustedUrl(url) {
|
||||
const separator = url.includes("?") ? "&" : "?";
|
||||
return `${url}${separator}preview=${Date.now()}`;
|
||||
}
|
||||
|
||||
function loadMapText(text, status) {
|
||||
@@ -194,10 +239,10 @@ function loadMapText(text, status) {
|
||||
state.selected = null;
|
||||
state.history = [];
|
||||
state.imageFailures.clear();
|
||||
preloadMapImages(state.map);
|
||||
fitWorldToCanvas();
|
||||
setStatus(status);
|
||||
refresh();
|
||||
preloadMapImages(state.map);
|
||||
} catch (error) {
|
||||
setStatus(`解析失败:${error.message}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user