- added local storage FS for saved games

This commit is contained in:
Ilya Shurumov 2021-07-09 21:19:00 +06:00 committed by InspirationByte
parent 6695633918
commit 644f08a447
3 changed files with 161 additions and 2 deletions

View File

@ -0,0 +1,147 @@
// Reusing all MEMFS functionality
// additionaly read data at mount
// and save data at some operations.
// Intended to use only for small files (like game settings),
// because LocalStorage is very limited
// and data saved as text in JSON format.
function LSFS() {
if (LSFS.mount) {
return LSFS;
}
var wrapCreateNode = wrapNode(MEMFS.createNode);
var wrap_node_ops = {
setattr: wrapSave(MEMFS.node_ops.setattr),
mknod: wrapNode(MEMFS.node_ops.mknod),
rename: wrapSave(MEMFS.node_ops.rename),
unlink: wrapSave(MEMFS.node_ops.unlink),
rmdir: wrapSave(MEMFS.node_ops.rmdir),
symlink: wrapNode(MEMFS.node_ops.symlink)
};
var wrap_stream_ops = {
write: wrapSave(MEMFS.stream_ops.write),
msync: wrapSave(MEMFS.stream_ops.msync)
};
var props = [ 'name', 'mode', 'rdev', 'link', 'usedBytes', 'timestamp' ];
LSFS.mount = mount;
return LSFS;
function wrapNode(fn) {
return function() {
var node = fn.apply(null, arguments);
setupNode(node);
return node;
}
}
function wrapSave(fn) {
return function(node) {
var res = fn.apply(null, arguments);
save(node);
return res;
}
}
function setupNode(node) {
var node_ops = {};
for (var op in node.node_ops) {
node_ops[op] = wrap_node_ops[op] || node.node_ops[op];
}
node.node_ops = node_ops;
var stream_ops = {};
for (var op in node.stream_ops) {
stream_ops[op] = wrap_stream_ops[op] || node.stream_ops[op];
}
node.stream_ops = stream_ops;
}
function filter(node) {
var result = {};
for (var key in node) {
if (props.indexOf(key) !== -1) {
result[key] = node[key];
}
}
if (node.contents) {
if (node.contents.length) {
result.contents = Array.apply([], node.contents);
} else {
result.contents = {};
for (var name in node.contents) {
result.contents[name] = filter(node.contents[name]);
}
}
}
return result;
}
function save(node) {
if (node.node) {
node = node.node;
}
var mount = node.mount;
if (!mount || !mount.opts || !mount.opts.key) {
return;
}
try {
localStorage.setItem(mount.opts.key, JSON.stringify(filter(mount.root)));
} catch (err) {}
}
function mount(mount) {
if (!mount.opts || !mount.opts.key) {
return;
}
var data;
try {
data = localStorage.getItem(mount.opts.key);
} catch (err) {}
if (data) {
try {
data = JSON.parse(data);
} catch (err) {}
}
var node = MEMFS.mount(mount);
setupNode(node);
load(node, mount, data);
return node;
}
function load(node, mount, data) {
node.mount = mount;
if (!data) {
return;
}
for (var key in data) {
if (props.indexOf(key) !== -1) {
node[key] = data[key];
}
}
if (data.contents) {
if (data.contents.length) {
node.contents = data.contents;
} else {
node.contents = {};
for (var name in data.contents) {
var childData = data.contents[name];
var childNode = wrapCreateNode(node, name, childData.mode, childData.rdev);
load(childNode, mount, childData);
}
}
}
}
}

View File

@ -7,7 +7,6 @@
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
<link href="https://fonts.googleapis.com/css?family=Oswald&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css?family=Oswald&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<style> <style>
.emscripten { .emscripten {
padding-right: 0; padding-right: 0;
@ -173,10 +172,21 @@
Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies - left) + '/' + this.totalDependencies + ')' : 'All downloads complete.'); Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies - left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
} }
}; };
Module.setStatus('Downloading...'); Module.setStatus('Downloading...');
// don't immediately run the game
Module['noInitialRun'] = true Module['noInitialRun'] = true
// for save data
Module.preRun.push(function() {
ENV.HOME = "/userstorage";
// create LSFS and mount 'data' local storage item into '/data' directory
FS.mkdir('/userstorage'); // for old versions use: FS.createFolder(FS.root, 'data', true, true);
FS.mount(LSFS(), { key: 'userstorage' }, '/userstorage');
})
window.onerror = function () { window.onerror = function () {
Module.setStatus('Exception thrown, see JavaScript console'); Module.setStatus('Exception thrown, see JavaScript console');
spinnerElement.style.display = 'none'; spinnerElement.style.display = 'none';
@ -202,6 +212,7 @@
callMain(["-ini", "demo_config.ini"]); callMain(["-ini", "demo_config.ini"]);
} }
</script> </script>
<script src="lsfs.js"></script>
{{{ SCRIPT }}} {{{ SCRIPT }}}
</body> </body>
</html> </html>

View File

@ -76,7 +76,8 @@ workspace "REDRIVER2"
targetextension ".html" targetextension ".html"
postbuildcommands { postbuildcommands {
"{COPY} " .. WEBSHELL_PATH .. "/style.css %{cfg.buildtarget.directory}" "{COPY} " .. WEBSHELL_PATH .. "/style.css %{cfg.buildtarget.directory}",
"{COPY} " .. WEBSHELL_PATH .. "/lsfs.js %{cfg.buildtarget.directory}"
} }
else else