Progress bar and steps while generating, loading, opening claims and travelling; saving chip (t30)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-24 18:54:06 -04:00
co-authored by Claude Opus 5.5
parent 4d5fca6dae
commit 66543bbd4b
13 changed files with 162 additions and 34 deletions
+19 -7
View File
@@ -40,12 +40,13 @@ function putWorldEntry(entry) {
await DB.put('worlds', list);
});
}
async function worldNewest(id) {
async function worldNewest(id, onProgress) {
if (onProgress) onProgress(0.05, 'Reading the save');
const a = await DB.get(`${id}:main`), b = await DB.get(`${id}:auto`);
const sv = a && b ? (a.savedAt >= b.savedAt ? a : b) : a || b;
if (!sv) return null;
const entry = (await listWorlds()).find(w => w.id === id);
return { ...sv, buffers: await unpackBuffers(sv.buffers), worldId: id, worldName: entry ? entry.name : 'World' };
return { ...sv, buffers: await unpackBuffers(sv.buffers, onProgress), worldId: id, worldName: entry ? entry.name : 'World' };
}
function deleteWorld(id) {
return worldWrite(async () => {
@@ -98,7 +99,10 @@ async function migrateWorlds() {
});
} catch (e) { toast('Could not move the old save. It has been kept. Reload to try again.'); throw e; }
}
let savingCount = 0;
async function saveWorld(slot, quiet) {
savingCount++;
const indicator = setTimeout(() => { if (!GAME.loading) $('saving').hidden = false; }, 150);
try {
const s = serializeWorld(), savedAt = Date.now(), playTime = GAME.playTime;
if (!GAME.worldId) { GAME.worldId = newWorldId(); GAME.worldName = `World ${(await listWorlds()).length + 1}`; }
@@ -116,10 +120,10 @@ async function saveWorld(slot, quiet) {
} catch (e) {
if (!quiet) toast('Could not save. Browser storage is unavailable in this view. Use Export world file instead.');
return false;
}
} finally { clearTimeout(indicator); if (!--savingCount) $('saving').hidden = true; }
}
async function newestSave() {
try { for (const entry of await listWorlds()) { const sv = await worldNewest(entry.id); if (sv) return sv; } return null; }
async function newestSave(onProgress) {
try { for (const entry of await listWorlds()) { const sv = await worldNewest(entry.id, onProgress); if (sv) return sv; } return null; }
catch (e) { return null; }
}
function b64FromBytes(u8) { let s = ''; const CH = 0x8000; for (let i = 0; i < u8.length; i += CH) s += String.fromCharCode.apply(null, u8.subarray(i, i + CH)); return btoa(s); }
@@ -137,9 +141,11 @@ async function packBuffers(buffers) {
}
return packed;
}
async function unpackBuffers(buffers) {
async function unpackBuffers(buffers, onProgress) {
let n = 0; const total = Object.keys(buffers).length;
const raw = {}, types = { Uint8Array, Uint8ClampedArray, Int8Array, Uint16Array, Int16Array, Uint32Array, Int32Array, Float32Array, Float64Array, BigInt64Array, BigUint64Array };
for (const k in buffers) {
if (onProgress) onProgress(0.1 + 0.6 * n++ / total, 'Unpacking');
const b = buffers[k];
if (ArrayBuffer.isView(b)) { raw[k] = b; continue; }
if (!b || b.gz !== true) throw new Error('Invalid saved buffer: ' + k);
@@ -148,6 +154,7 @@ async function unpackBuffers(buffers) {
if (!bytes) throw new Error('This browser cannot decompress saved worlds.');
raw[k] = new C(bytes.buffer, bytes.byteOffset, bytes.byteLength / C.BYTES_PER_ELEMENT);
}
if (onProgress) onProgress(0.7, 'Unpacking');
return raw;
}
async function exportWorld() {
@@ -177,22 +184,27 @@ async function exportWorld() {
catch (e) { if (e && e.code !== 'declined') toast('The world file was not saved.'); }
}
async function importWorldFile(file) {
const progress = (f, s) => showLoading(true, f, s, 'Loading world');
progress(0.05, 'Reading the save');
try {
const obj = JSON.parse(await file.text());
if (obj.format !== 'deepgrain-world') throw new Error('Not a Deepgrain world file.');
const bufs = {};
const T = { Uint8Array, Uint16Array, Int16Array, Float32Array, Int32Array };
let n = 0; const total = Object.keys(obj.buffers).length;
for (const k in obj.buffers) {
progress(0.1 + 0.6 * n++ / total, 'Unpacking');
const b = obj.buffers[k]; let bytes = bytesFromB64(b.b64);
if (b.gz) bytes = await gz(bytes, true);
const C = T[b.type] || Uint8Array;
bufs[k] = new C(bytes.buffer, bytes.byteOffset, bytes.byteLength / C.BYTES_PER_ELEMENT);
}
const id = newWorldId(), name = `Imported ${obj.meta.seed}`.slice(0, 40);
if (!await startFromSave({ meta: obj.meta, buffers: bufs, worldId: id, worldName: name })) return;
if (!await startFromSave({ meta: obj.meta, buffers: bufs, worldId: id, worldName: name }, progress)) return;
if (!await saveWorld('auto')) return;
toast('World imported.');
} catch (e) { toast('That file could not be loaded: ' + (e.message || 'unknown error')); }
finally { showLoading(false); }
}
// ---------- Blueprint library ----------