Title screen, pause menu, settings dialog and savegames
- title screen (continue/new/load/settings/help) and Esc pause menu - settings: language & sound, camera, graphics, game, rebindable keys; stored in localStorage and in every savegame (always applied on load) - savegames as JSON (.dcsave): download, load via file picker or drag & drop - autosave to localStorage every 2 minutes and when the tab is hidden/closed - configurable wall detail, light count, interface size, game speed, hints - audio behind a cargo feature so native tests run (cargo test --no-default-features) - savegame round-trip test Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
fbf6f223fc
commit
fb7dab3683
17 files changed
+1742
-345
No files matched your search
+54
-5
@@ -1,7 +1,9 @@
|
||||
// DungeonCraft browser plugin for miniquad: localStorage access for the Rust code.
|
||||
// DungeonCraft browser plugin for miniquad: storage, file download/upload, save-on-leave.
|
||||
(function () {
|
||||
"use strict";
|
||||
var pending = null;
|
||||
var pending = null; // value handed over by dc_storage_get
|
||||
var file = null; // bytes of a file chosen via the file picker
|
||||
var cache = {}; // key -> string, persisted to localStorage when the page is hidden/closed
|
||||
|
||||
function bytes(ptr, len) {
|
||||
return new Uint8Array(wasm_memory.buffer, ptr, len);
|
||||
@@ -9,23 +11,70 @@
|
||||
function str(ptr, len) {
|
||||
return new TextDecoder().decode(bytes(ptr, len));
|
||||
}
|
||||
function flushCache() {
|
||||
for (var k in cache) {
|
||||
try { window.localStorage.setItem(k, cache[k]); } catch (e) { }
|
||||
}
|
||||
}
|
||||
window.addEventListener("pagehide", flushCache);
|
||||
document.addEventListener("visibilitychange", function () {
|
||||
if (document.visibilityState === "hidden") flushCache();
|
||||
});
|
||||
|
||||
// hidden <input type=file> for loading savegames
|
||||
var input = document.createElement("input");
|
||||
input.type = "file";
|
||||
input.accept = ".dcsave,.json,application/json";
|
||||
input.style.display = "none";
|
||||
input.addEventListener("change", function () {
|
||||
var f = input.files && input.files[0];
|
||||
if (!f) return;
|
||||
f.arrayBuffer().then(function (buf) { file = new Uint8Array(buf); });
|
||||
input.value = "";
|
||||
});
|
||||
document.addEventListener("DOMContentLoaded", function () { document.body.appendChild(input); });
|
||||
|
||||
function register(importObject) {
|
||||
importObject.env.dc_storage_get = function (kp, kl) {
|
||||
var env = importObject.env;
|
||||
env.dc_storage_get = function (kp, kl) {
|
||||
var v = null;
|
||||
try { v = window.localStorage.getItem(str(kp, kl)); } catch (e) { }
|
||||
if (v === null) { pending = null; return -1; }
|
||||
pending = new TextEncoder().encode(v);
|
||||
return pending.length;
|
||||
};
|
||||
importObject.env.dc_storage_take = function (ptr) {
|
||||
env.dc_storage_take = function (ptr) {
|
||||
if (pending === null) return;
|
||||
bytes(ptr, pending.length).set(pending);
|
||||
pending = null;
|
||||
};
|
||||
importObject.env.dc_storage_set = function (kp, kl, vp, vl) {
|
||||
env.dc_storage_set = function (kp, kl, vp, vl) {
|
||||
try { window.localStorage.setItem(str(kp, kl), str(vp, vl)); } catch (e) { }
|
||||
};
|
||||
env.dc_cache_set = function (kp, kl, vp, vl) {
|
||||
cache[str(kp, kl)] = str(vp, vl);
|
||||
};
|
||||
env.dc_download = function (np, nl, dp, dl) {
|
||||
var blob = new Blob([bytes(dp, dl).slice()], { type: "application/json" });
|
||||
var a = document.createElement("a");
|
||||
a.href = URL.createObjectURL(blob);
|
||||
a.download = str(np, nl);
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
setTimeout(function () { URL.revokeObjectURL(a.href); a.remove(); }, 1000);
|
||||
};
|
||||
env.dc_open_file = function () {
|
||||
file = null;
|
||||
input.click();
|
||||
};
|
||||
env.dc_file_poll = function () {
|
||||
return file === null ? -1 : file.length;
|
||||
};
|
||||
env.dc_file_take = function (ptr) {
|
||||
if (file === null) return;
|
||||
bytes(ptr, file.length).set(file);
|
||||
file = null;
|
||||
};
|
||||
}
|
||||
|
||||
miniquad_add_plugin({ register_plugin: register, version: 1, name: "dungeoncraft" });
|
||||
|
||||
Reference in new issue
Block a user