Huge world size, and saves are gzip-compressed (about 60x smaller) (t3)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -58,6 +58,7 @@
|
||||
<option value="2048x1024">Small · 2048 × 1024</option>
|
||||
<option value="3072x1280" selected>Medium · 3072 × 1280</option>
|
||||
<option value="4096x1536">Large · 4096 × 1536</option>
|
||||
<option value="6144x2048">Huge · 6144 × 2048</option>
|
||||
</select>
|
||||
</label>
|
||||
<button class="btn primary full" id="btn-generate">Generate and start</button>
|
||||
|
||||
+27
-4
@@ -45,7 +45,7 @@ async function worldNewest(id) {
|
||||
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, worldId: id, worldName: entry ? entry.name : 'World' };
|
||||
return { ...sv, buffers: await unpackBuffers(sv.buffers), worldId: id, worldName: entry ? entry.name : 'World' };
|
||||
}
|
||||
function deleteWorld(id) {
|
||||
return worldWrite(async () => {
|
||||
@@ -75,8 +75,9 @@ async function migrateWorlds() {
|
||||
for (const [slot, old] of [['main', a], ['auto', b]]) if (old) {
|
||||
const copy = await DB.get(`${id}:${slot}`);
|
||||
if (!copy || JSON.stringify(copy.meta) !== JSON.stringify(old.meta) || copy.savedAt !== old.savedAt || copy.playTime !== old.playTime) throw new Error('Save copy failed.');
|
||||
for (const k in old.buffers) {
|
||||
const x = old.buffers[k], y = copy.buffers[k];
|
||||
const original = await unpackBuffers(old.buffers), copied = await unpackBuffers(copy.buffers);
|
||||
for (const k in original) {
|
||||
const x = original[k], y = copied[k];
|
||||
if (!y || x.constructor !== y.constructor || x.length !== y.length || !x.every((v, i) => v === y[i])) throw new Error('Save copy failed.');
|
||||
}
|
||||
}
|
||||
@@ -91,12 +92,13 @@ async function saveWorld(slot, quiet) {
|
||||
const s = serializeWorld(), savedAt = Date.now(), playTime = GAME.playTime;
|
||||
if (!GAME.worldId) { GAME.worldId = newWorldId(); GAME.worldName = `World ${(await listWorlds()).length + 1}`; }
|
||||
const id = GAME.worldId, name = GAME.worldName;
|
||||
const buffers = await packBuffers(s.buffers);
|
||||
await worldWrite(async () => {
|
||||
const list = await listWorlds();
|
||||
let entry = list.find(w => w.id === id);
|
||||
if (!entry) { entry = { id, name, createdAt: savedAt }; list.push(entry); }
|
||||
Object.assign(entry, { savedAt, playTime, seed: s.meta.seed, w: s.meta.W, h: s.meta.H });
|
||||
await DB.op('readwrite', st => { st.put({ meta: s.meta, buffers: s.buffers, savedAt, playTime }, `${id}:${slot}`); st.put(list, 'worlds'); });
|
||||
await DB.op('readwrite', st => { st.put({ meta: s.meta, buffers, savedAt, playTime }, `${id}:${slot}`); st.put(list, 'worlds'); });
|
||||
});
|
||||
if (!quiet) toast(slot === 'auto' ? 'Autosaved.' : 'World saved.');
|
||||
return true;
|
||||
@@ -116,6 +118,27 @@ async function gz(u8, inflate) {
|
||||
const st = new Blob([u8]).stream().pipeThrough(inflate ? new DecompressionStream('gzip') : new CompressionStream('gzip'));
|
||||
return new Uint8Array(await new Response(st).arrayBuffer());
|
||||
}
|
||||
async function packBuffers(buffers) {
|
||||
const packed = {};
|
||||
for (const k in buffers) {
|
||||
const arr = buffers[k], bytes = await gz(new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength));
|
||||
packed[k] = bytes ? { type: arr.constructor.name, gz: true, bytes } : arr;
|
||||
}
|
||||
return packed;
|
||||
}
|
||||
async function unpackBuffers(buffers) {
|
||||
const raw = {}, types = { Uint8Array, Uint8ClampedArray, Int8Array, Uint16Array, Int16Array, Uint32Array, Int32Array, Float32Array, Float64Array, BigInt64Array, BigUint64Array };
|
||||
for (const k in buffers) {
|
||||
const b = buffers[k];
|
||||
if (ArrayBuffer.isView(b)) { raw[k] = b; continue; }
|
||||
if (!b || b.gz !== true) throw new Error('Invalid saved buffer: ' + k);
|
||||
if (!Object.hasOwn(types, b.type)) throw new Error('Unknown saved buffer type: ' + b.type);
|
||||
const bytes = await gz(b.bytes, true), C = types[b.type];
|
||||
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);
|
||||
}
|
||||
return raw;
|
||||
}
|
||||
async function exportWorld() {
|
||||
const s = serializeWorld();
|
||||
const out = { format: 'deepgrain-world', v: 1, meta: s.meta, buffers: {} };
|
||||
|
||||
Reference in New Issue
Block a user