1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2025-12-12 02:22:26 +01:00
Files
OpenRCT2/emscripten/static/index.js
2025-04-08 11:26:23 +00:00

270 lines
8.8 KiB
JavaScript

/*****************************************************************************
* Copyright (c) 2014-2025 OpenRCT2 developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
(async () =>
{
await new Promise(res => window.addEventListener("DOMContentLoaded", res));
if (!window.SharedArrayBuffer)
{
document.getElementById("loadingWebassembly").innerText = "Error! SharedArrayBuffer is not defined. This page required the CORP and COEP response headers.";
return;
}
if (!window.WebAssembly)
{
document.getElementById("loadingWebassembly").innerText = "Error! This page requires WebAssembly. Please upgrade your browser or enable WebAssembly support.";
return;
}
let assets;
try
{
let req = await fetch("openrct2.zip");
if (!req.ok) {
throw new Error("Response is not ok!")
}
let data = await req.blob();
let zip = new JSZip();
let contents = await zip.loadAsync(data);
assets = {
js: URL.createObjectURL(new Blob([await zip.file("openrct2.js").async("uint8array")], {type: 'application/json'})),
wasm: URL.createObjectURL(new Blob([await zip.file("openrct2.wasm").async("uint8array")], {type: 'application/wasm'}))
}
}
catch(e)
{
assets = null;
console.warn("Failed to fetch openrct2.zip. Will pull not-compressed files", e);
}
await new Promise(resolve => {
const script = document.createElement("script");
script.src = assets === null ? "openrct2.js" : assets.js;
script.addEventListener("load", resolve);
script.addEventListener("error", (e) => {
document.getElementById("loadingWebassembly").innerText = "Error loading openrct2.js!";
console.error(e);
});
document.body.appendChild(script);
})
window.Module = await window.OPENRCT2_WEB(
{
noInitialRun: true,
arguments: [],
preRun: [],
postRun: [],
canvas: document.getElementById("canvas"),
print: function(msg)
{
console.log(msg);
},
printErr: function(msg)
{
console.log(msg);
},
totalDependencies: 0,
monitorRunDependencies: () => {},
locateFile: function(fileName)
{
if (assets !== null && fileName === "openrct2.wasm")
{
return assets.wasm;
}
console.log("loading", fileName);
return fileName;
}
});
Module.FS.mkdir("/persistent");
Module.FS.mount(Module.FS.filesystems.IDBFS, {autoPersist: true}, '/persistent');
Module.FS.mkdir("/RCT");
Module.FS.mount(Module.FS.filesystems.IDBFS, {autoPersist: true}, '/RCT');
Module.FS.mkdir("/OpenRCT2");
Module.FS.mount(Module.FS.filesystems.IDBFS, {autoPersist: true}, '/OpenRCT2');
await new Promise(res => Module.FS.syncfs(true, res));
let configExists = fileExists("/persistent/config.ini");
if (!configExists)
{
Module.FS.writeFile("/persistent/config.ini", `
[general]
game_path = "/RCT"
uncap_fps = true
window_scale = 1.750000
`);
}
const assetsOK = await updateAssets();
if (!assetsOK)
{
return
}
Module.FS.writeFile("/OpenRCT2/changelog.txt", `EMSCRIPTEN --- README
Since we're running in the web browser, we don't have direct access to the file system.
All save data is saved under the directory /persistent.
ALWAYS be sure to save to /persistent/saves when saving a game! Otherwise it will be wiped!
You can import/export the /persistent folder in the options menu.`);
document.getElementById("loadingWebassembly").remove();
let filesFound = fileExists("/RCT/Data/ch.dat");
if (!filesFound)
{
document.getElementById("beforeLoad").style.display = "";
await new Promise(res =>
{
document.getElementById("selectFile").addEventListener("change", async (e) =>
{
if (await extractZip(e.target.files[0], (zip) =>
{
if (zip !== null)
{
if (zip.file("Data/ch.dat"))
{
document.getElementById("beforeLoad").remove();
return "/RCT/";
}
else if (zip.file("RCT/Data/ch.dat"))
{
document.getElementById("beforeLoad").remove();
return "/";
}
}
document.getElementById("statusMsg").innerText = "That doesn't look right. Your file should be a zip file containing Data/ch.dat. Please select your OpenRCT2 contents (zip file):";
return false;
}))
{
res();
}
});
});
}
Module.canvas.style.display = "";
Module.callMain(["--user-data-path=/persistent/", "--openrct2-data-path=/OpenRCT2/"]);
})();
async function updateAssets() {
let currentVersion = "";
try {
currentVersion = Module.FS.readFile("/OpenRCT2/version", {encoding: "utf8"});
console.log("Found asset version", currentVersion);
} catch(e) {
console.log("No asset version found");
};
let assetsVersion = "DEBUG";
try {
assetsVersion = Module.ccall("GetVersion", "string");
} catch(e) {
console.warn("Could not call 'GetVersion'! Is it added to EXPORTED_FUNCTIONS? Is ccall added to EXPORTED_RUNTIME_METHODS?");
};
//Always pull assets on a debug build
if (currentVersion !== assetsVersion || assetsVersion.includes("DEBUG"))
{
console.log("Updating assets to", assetsVersion);
document.getElementById("loadingWebassembly").innerText = "Asset update found. Downloading...";
await clearDatabase("/OpenRCT2/");
// Fetch the assets.zip file
const response = await fetch("assets.zip");
if (!response.ok) {
if (response.status === 404) {
document.getElementById("loadingWebassembly").innerText = "Error! Assets file not found (404).";
} else {
document.getElementById("loadingWebassembly").innerText = `Error! Failed to download assets (status: ${response.status}).`;
}
return false;
} else {
document.getElementById("loadingWebassembly").innerText = "Downloaded assets.zip";
}
await extractZip(await response.blob(), () => {
return "/OpenRCT2/";
});
Module.FS.writeFile("/OpenRCT2/version", assetsVersion.toString());
}
return true;
}
async function extractZip(data, checkZip) {
let zip = new JSZip();
let contents;
try {
contents = await zip.loadAsync(data);
} catch(e) {
if (typeof checkZip === "function")
{
checkZip(null);
}
throw e;
}
let base = "/";
if (typeof checkZip === "function")
{
const cont = checkZip(contents);
if (cont === false) return false;
base = cont;
}
for (const k in contents.files) {
const entry = contents.files[k];
if (entry.dir)
{
try {
Module.FS.mkdir(base+k);
} catch(e) {}
}
else
{
Module.FS.writeFile(base+k, await entry.async("uint8array"));
}
}
return true;
}
async function clearDatabase(dir) {
await new Promise(res => Module.FS.syncfs(false, res));
const processFolder = (path) => {
let contents;
try {
contents = Module.FS.readdir(path);
} catch(e) {
return;
}
contents.forEach((entry) => {
if ([".", ".."].includes(entry)) return;
try {
Module.FS.readFile(path + entry);
Module.FS.unlink(path + entry);
} catch(e) {
processFolder(path + entry + "/");
}
})
if (path === dir) return;
try {
Module.FS.rmdir(path, {recursive: true});
} catch(e) {
console.log("Could not remove:", path);
}
}
processFolder(dir);
await new Promise(res => Module.FS.syncfs(false, res));
}
function fileExists(path) {
try {
Module.FS.readFile(path);
return true;
} catch(e) {};
return false;
}