2020-10-19 21:43:10 +00:00
|
|
|
// Canvas used for image generation
|
|
|
|
var generationCanvas = document.createElement('canvas')
|
2020-10-20 06:02:31 +00:00
|
|
|
window.fileAsyncCache = {};
|
|
|
|
|
|
|
|
window.getMappingKey = function(file) {
|
|
|
|
return file.toLowerCase().replace(new RegExp("\\.[^/.]+$"), "")
|
|
|
|
}
|
2020-10-19 21:43:10 +00:00
|
|
|
|
|
|
|
window.loadFileAsync = function(fullPath, bitmap, callback) {
|
|
|
|
// noop
|
|
|
|
callback = callback || (() => {});
|
|
|
|
|
2020-10-20 06:02:31 +00:00
|
|
|
// Get mapping key
|
|
|
|
const mappingKey = getMappingKey(fullPath);
|
|
|
|
const mappingValue = mapping[mappingKey];
|
2020-10-19 18:12:15 +00:00
|
|
|
|
|
|
|
// Check if already loaded
|
2020-10-20 06:02:31 +00:00
|
|
|
if (window.fileAsyncCache.hasOwnProperty(mappingKey)) return callback();
|
2020-10-19 18:12:15 +00:00
|
|
|
|
|
|
|
// Show spinner
|
2020-10-19 21:43:10 +00:00
|
|
|
if (!bitmap && window.setBusy) window.setBusy();
|
2020-10-19 18:12:15 +00:00
|
|
|
|
|
|
|
// Check if this is a folder
|
|
|
|
if (!mappingValue || mappingValue.endsWith("h=")) {
|
|
|
|
console.error("Skipping loading", fullPath, mappingValue);
|
|
|
|
return callback();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get target URL
|
|
|
|
const iurl = "gameasync/" + mappingValue;
|
|
|
|
|
|
|
|
// Get path and filename
|
|
|
|
const path = "/game/" + mappingValue.substring(0, mappingValue.lastIndexOf("/"));
|
|
|
|
const filename = mappingValue.substring(mappingValue.lastIndexOf("/") + 1).split("?")[0];
|
|
|
|
|
2020-10-19 21:43:10 +00:00
|
|
|
// Main loading function
|
|
|
|
const load = (cb1) => {
|
|
|
|
getLazyAsset(iurl, filename, (data) => {
|
|
|
|
FS.createPreloadedFile(path, filename, new Uint8Array(data), true, true, function() {
|
2020-10-20 06:02:31 +00:00
|
|
|
window.fileAsyncCache[mappingKey] = 1;
|
2020-10-19 21:43:10 +00:00
|
|
|
if (!bitmap && window.setNotBusy) window.setNotBusy();
|
|
|
|
if (window.fileLoadedAsync) window.fileLoadedAsync(fullPath);
|
|
|
|
callback();
|
|
|
|
if (cb1) cb1();
|
2020-10-19 22:18:31 +00:00
|
|
|
}, console.error, false, false, () => {
|
|
|
|
try { FS.unlink(path + "/" + filename); } catch (err) {}
|
|
|
|
});
|
2020-10-19 21:43:10 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// Show progress if doing it synchronously only
|
|
|
|
if (bitmap && bitmapSizeMapping[mappingKey]) {
|
|
|
|
// Get image
|
|
|
|
const sm = bitmapSizeMapping[mappingKey];
|
|
|
|
generationCanvas.width = sm[0];
|
|
|
|
generationCanvas.height = sm[1];
|
|
|
|
|
2020-10-20 00:18:27 +00:00
|
|
|
// Draw
|
|
|
|
var img = new Image;
|
|
|
|
img.onload = function(){
|
|
|
|
const ctx = generationCanvas.getContext('2d');
|
|
|
|
ctx.drawImage(img, 0, 0, sm[0], sm[1]);
|
|
|
|
|
|
|
|
// Create dummy from data uri
|
|
|
|
FS.createPreloadedFile(path, filename, generationCanvas.toDataURL(), true, true, function() {
|
|
|
|
// Return control to C++
|
|
|
|
callback(); callback = () => {};
|
|
|
|
|
|
|
|
// Lazy load and refresh
|
|
|
|
load(() => {
|
|
|
|
const reloadBitmap = Module.cwrap('reloadBitmap', 'number', ['number'])
|
|
|
|
reloadBitmap(bitmap);
|
|
|
|
});
|
|
|
|
}, console.error, false, false, () => {
|
|
|
|
try { FS.unlink(path + "/" + filename); } catch (err) {}
|
2020-10-19 21:43:10 +00:00
|
|
|
});
|
2020-10-20 00:18:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
img.src = sm[2];
|
2020-10-19 21:43:10 +00:00
|
|
|
} else {
|
|
|
|
if (bitmap) {
|
|
|
|
console.warn('No sizemap for image', mappingKey);
|
|
|
|
}
|
|
|
|
load();
|
|
|
|
}
|
2020-10-19 18:12:15 +00:00
|
|
|
}
|
2020-10-20 06:02:31 +00:00
|
|
|
|
|
|
|
|
2020-10-20 11:43:37 +00:00
|
|
|
window.saveFile = function(filename, localOnly) {
|
|
|
|
const fpath = '/game/' + filename;
|
|
|
|
if (!FS.analyzePath(fpath).exists) return;
|
|
|
|
|
|
|
|
const buf = FS.readFile(fpath);
|
2020-10-20 10:07:49 +00:00
|
|
|
localforage.setItem(namespace + filename, buf);
|
2020-10-20 06:02:31 +00:00
|
|
|
|
|
|
|
localforage.getItem(namespace, function(err, res) {
|
|
|
|
if (err || !res) res = {};
|
2020-10-20 11:43:37 +00:00
|
|
|
res[filename] = { t: Number(FS.stat(fpath).mtime) };
|
2020-10-20 06:02:31 +00:00
|
|
|
localforage.setItem(namespace, res);
|
|
|
|
});
|
2020-10-20 07:49:46 +00:00
|
|
|
|
2020-10-20 11:43:37 +00:00
|
|
|
if (!localOnly) {
|
|
|
|
(window.saveCloudFile || (()=>{}))(filename, buf);
|
|
|
|
}
|
2020-10-20 06:02:31 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
var loadFiles = function() {
|
2020-10-20 11:43:37 +00:00
|
|
|
localforage.getItem(namespace, function(err, folder) {
|
|
|
|
if (err || !folder) return;
|
|
|
|
console.log('Locally stored savefiles:', folder);
|
2020-10-20 06:02:31 +00:00
|
|
|
|
2020-10-20 11:43:37 +00:00
|
|
|
Object.keys(folder).forEach((key) => {
|
|
|
|
const meta = folder[key];
|
2020-10-20 06:02:31 +00:00
|
|
|
localforage.getItem(namespace + key, (err, res) => {
|
2020-10-20 11:43:37 +00:00
|
|
|
if (err || !res) return;
|
2020-10-20 06:02:31 +00:00
|
|
|
|
2020-10-20 10:07:49 +00:00
|
|
|
// Don't overwrite existing files
|
2020-10-20 11:43:37 +00:00
|
|
|
const fpath = '/game/' + key;
|
|
|
|
if (FS.analyzePath(fpath).exists) return;
|
|
|
|
|
|
|
|
FS.writeFile(fpath, res);
|
2020-10-20 10:07:49 +00:00
|
|
|
|
2020-10-20 11:43:37 +00:00
|
|
|
if (Number.isInteger(meta.t)) {
|
|
|
|
FS.utime(fpath, meta.t, meta.t);
|
|
|
|
}
|
2020-10-20 06:02:31 +00:00
|
|
|
});
|
|
|
|
});
|
2020-10-20 11:43:37 +00:00
|
|
|
}, console.error);
|
2020-10-20 07:49:46 +00:00
|
|
|
|
|
|
|
(window.loadCloudFiles || (()=>{}))();
|
2020-10-20 06:02:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var createDummies = function() {
|
|
|
|
// Base directory
|
|
|
|
FS.mkdir('/game');
|
|
|
|
|
|
|
|
// Create dummy objects
|
2020-10-20 14:07:08 +00:00
|
|
|
for (var i = 0; i < mappingArray.length; i++) {
|
2020-10-20 06:02:31 +00:00
|
|
|
// Get filename
|
2020-10-20 14:07:08 +00:00
|
|
|
const file = mappingArray[i][1];
|
2020-10-20 06:02:31 +00:00
|
|
|
const filename = '/game/' + file.split("?")[0];
|
|
|
|
|
|
|
|
// Check if folder
|
|
|
|
if (file.endsWith('h=')) {
|
2020-10-20 14:07:08 +00:00
|
|
|
FS.mkdir(filename);
|
|
|
|
} else {
|
|
|
|
FS.writeFile(filename, '1');
|
2020-10-20 06:02:31 +00:00
|
|
|
}
|
2020-10-20 14:07:08 +00:00
|
|
|
}
|
2020-10-20 06:02:31 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
window.setBusy = function() {
|
|
|
|
document.getElementById('spinner').style.opacity = "0.5";
|
|
|
|
};
|
|
|
|
|
|
|
|
window.setNotBusy = function() {
|
|
|
|
document.getElementById('spinner').style.opacity = "0";
|
|
|
|
};
|
|
|
|
|
|
|
|
window.onerror = function() {
|
|
|
|
console.error("An error occured!")
|
|
|
|
};
|
|
|
|
|
|
|
|
function preloadList(jsonArray) {
|
|
|
|
jsonArray.forEach((file) => {
|
|
|
|
const mappingKey = getMappingKey(file);
|
|
|
|
const mappingValue = mapping[mappingKey];
|
|
|
|
if (!mappingValue || window.fileAsyncCache[mappingKey]) return;
|
|
|
|
|
|
|
|
// Get path and filename
|
|
|
|
const path = "/game/" + mappingValue.substring(0, mappingValue.lastIndexOf("/"));
|
|
|
|
const filename = mappingValue.substring(mappingValue.lastIndexOf("/") + 1).split("?")[0];
|
|
|
|
|
|
|
|
// Preload the asset
|
2020-10-20 15:41:06 +00:00
|
|
|
getLazyAsset("gameasync/" + mappingValue, filename, (data) => {
|
|
|
|
if (!data) return;
|
|
|
|
|
|
|
|
FS.createPreloadedFile(path, filename, new Uint8Array(data), true, true, function() {
|
|
|
|
window.fileAsyncCache[mappingKey] = 1;
|
|
|
|
}, console.error, false, false, () => {
|
|
|
|
try { FS.unlink(path + "/" + filename); } catch (err) {}
|
|
|
|
});
|
|
|
|
}, true);
|
2020-10-20 06:02:31 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
window.fileLoadedAsync = function(file) {
|
|
|
|
document.title = wTitle;
|
|
|
|
|
|
|
|
if (!(/.*Map.*rxdata/i.test(file))) return;
|
|
|
|
|
|
|
|
fetch('preload/' + file + '.json')
|
|
|
|
.then(function(response) {
|
|
|
|
return response.json();
|
|
|
|
})
|
|
|
|
.then(function(jsonResponse) {
|
|
|
|
setTimeout(() => {
|
|
|
|
preloadList(jsonResponse);
|
|
|
|
}, 200);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2020-10-20 15:41:06 +00:00
|
|
|
var activeStreams = [];
|
|
|
|
function getLazyAsset(url, filename, callback, noretry) {
|
2020-10-20 06:02:31 +00:00
|
|
|
const xhr = new XMLHttpRequest();
|
|
|
|
xhr.responseType = "arraybuffer";
|
|
|
|
const pdiv = document.getElementById("progress");
|
|
|
|
let abortTimer = 0;
|
|
|
|
|
2020-10-20 15:41:06 +00:00
|
|
|
const end = (message) => {
|
|
|
|
pdiv.innerHTML = `${filename} - ${message}`;
|
|
|
|
activeStreams.splice(activeStreams.indexOf(filename), 1);
|
|
|
|
if (activeStreams.length === 0) {
|
|
|
|
pdiv.style.opacity = '0';
|
|
|
|
}
|
|
|
|
clearTimeout(abortTimer);
|
|
|
|
}
|
|
|
|
|
2020-10-20 06:02:31 +00:00
|
|
|
const retry = () => {
|
|
|
|
xhr.abort();
|
2020-10-20 15:41:06 +00:00
|
|
|
|
|
|
|
if (noretry) {
|
|
|
|
end('skip'); callback(null);
|
|
|
|
} else {
|
|
|
|
activeStreams.splice(activeStreams.indexOf(filename), 1);
|
|
|
|
getLazyAsset(url, filename, callback);
|
|
|
|
}
|
2020-10-20 06:02:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
xhr.onreadystatechange = function() {
|
|
|
|
if (xhr.readyState == XMLHttpRequest.DONE && xhr.status >= 200 && xhr.status < 400) {
|
2020-10-20 15:41:06 +00:00
|
|
|
end('done');
|
2020-10-20 06:02:31 +00:00
|
|
|
callback(xhr.response);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
xhr.onprogress = function (event) {
|
|
|
|
const loaded = Math.round(event.loaded / 1024);
|
|
|
|
const total = Math.round(event.total / 1024);
|
|
|
|
pdiv.innerHTML = `${filename} - ${loaded}KB / ${total}KB`;
|
|
|
|
|
|
|
|
clearTimeout(abortTimer);
|
2020-10-20 06:43:36 +00:00
|
|
|
abortTimer = setTimeout(retry, 10000);
|
2020-10-20 06:02:31 +00:00
|
|
|
};
|
|
|
|
xhr.open('GET', url);
|
|
|
|
xhr.send();
|
|
|
|
|
2020-10-20 15:41:06 +00:00
|
|
|
pdiv.innerHTML = `${filename} - start`;
|
|
|
|
pdiv.style.opacity = '0.5';
|
2020-10-20 06:02:31 +00:00
|
|
|
|
2020-10-20 15:41:06 +00:00
|
|
|
activeStreams.push(filename);
|
2020-10-20 06:02:31 +00:00
|
|
|
|
2020-10-20 06:43:36 +00:00
|
|
|
abortTimer = setTimeout(retry, 10000);
|
2020-10-20 06:02:31 +00:00
|
|
|
}
|