new web interface and loading progress
This commit is contained in:
parent
b8a53b9c9d
commit
bc45f6027e
@ -1,9 +0,0 @@
|
||||
/* DELETE
|
||||
;run\(\);
|
||||
*/
|
||||
|
||||
|
||||
/* DELETE
|
||||
if ?\(!calledRun\)\s*?run\(\);
|
||||
*/
|
||||
|
@ -1,35 +1,97 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
|
||||
<title>SuperTuxKart</title>
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico">
|
||||
<script src="/game/supertuxkart.js"></script>
|
||||
<script>
|
||||
//emscripten only tells us if the runtime is ready once it starts main
|
||||
//so cancel running main the first time around so we can store when it is ready
|
||||
globalThis.ready = false;
|
||||
var real_run = run;
|
||||
run = () => {
|
||||
if (globalThis.ready) {
|
||||
real_run();
|
||||
}
|
||||
globalThis.ready = true;
|
||||
}
|
||||
</script>
|
||||
<script src="/script.js" type="module" defer></script>
|
||||
|
||||
<style>
|
||||
* {
|
||||
font-family: Arial, sans-serif;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
p {
|
||||
font-size: 12px;
|
||||
margin: 4px;
|
||||
}
|
||||
body {
|
||||
margin: 0px;
|
||||
}
|
||||
#canvas {
|
||||
background-color: #222222;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
z-index: 1;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
#info_container {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 440px;
|
||||
height: 260px;
|
||||
margin-left: -220px;
|
||||
margin-top: -130px;
|
||||
z-index: 2;
|
||||
background-color: white;
|
||||
padding: 12px;
|
||||
padding-top: 6px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
#header_bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 18px;
|
||||
}
|
||||
#status_bar {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
align-items: center;
|
||||
margin-top: 12px;
|
||||
gap: 6px;
|
||||
}
|
||||
#start_button {
|
||||
border: none;
|
||||
outline: none;
|
||||
padding: 8px;
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<canvas id="canvas"></canvas>
|
||||
<br>
|
||||
<div id="status_bar">
|
||||
<button id="start_button" disabled>Start Game</button>
|
||||
<p id="status_text">Downloading game files...</p>
|
||||
<div id="info_container">
|
||||
<div id="header_bar">
|
||||
<img src="/supertuxkart_64.png">
|
||||
<h1 style="margin: 0px;">SuperTuxKart Wasm</h1>
|
||||
</div>
|
||||
<p>This is an experimental port of SuperTuxKart to the browser using WebAssembly and Emscripten. Currently, everything works except for some rendering APIs and networking.</p>
|
||||
<p>There is a 700MB initial download required to play, and the game will require around 1GB of memory.</p>
|
||||
<p>This web port was made by <a href="https://github.com/ading2210/">ading2210</a>, and the source code is located at <a href="https://github.com/ading2210/stk-code/tree/wasm">github.com/ading2210/stk-code</a>.</p>
|
||||
<p>If you want to check on the status of this port, take a look at the <a href="https://github.com/supertuxkart/stk-code/pull/5106/">corresponding pull request</a> in the SuperTuxKart repository.</p>
|
||||
<div id="status_bar">
|
||||
<button id="start_button" disabled>Start Game</button>
|
||||
<p id="status_text"></p>
|
||||
</div>
|
||||
</div>
|
||||
<p>This web port was made by <a href="https://github.com/ading2210/">ading2210</a>.</p>
|
||||
<p>The source code is located at <a href="https://github.com/ading2210/stk-code/tree/wasm">github.com/ading2210/stk-code</a>.</p>
|
||||
</body>
|
||||
</html>
|
@ -8,6 +8,7 @@ let idbfs_mount = null;
|
||||
|
||||
let start_button = document.getElementById("start_button");
|
||||
let status_text = document.getElementById("status_text");
|
||||
let info_container = document.getElementById("info_container");
|
||||
|
||||
function load_db() {
|
||||
if (db) return db;
|
||||
@ -103,24 +104,33 @@ async function write_db_chunks(key, data) {
|
||||
}
|
||||
|
||||
async function download_chunks(url) {
|
||||
let path = url.split("/");
|
||||
let filename = path.pop();
|
||||
let base_url = path.join("/");
|
||||
|
||||
status_text.textContent = `Downloading manifest for ${filename}...`;
|
||||
let r1 = await fetch(url + ".manifest");
|
||||
let manifest = (await r1.text()).split("\n");
|
||||
let size = parseInt(manifest.shift());
|
||||
manifest.pop();
|
||||
|
||||
let path = url.split("/");
|
||||
path.pop();
|
||||
let base_url = path.join("/");
|
||||
|
||||
let offset = 0;
|
||||
let chunk = null;
|
||||
let array = new Uint8Array(size);
|
||||
let chunk_count = manifest.length;
|
||||
let current_chunk = 1;
|
||||
|
||||
while (chunk = manifest.shift()) {
|
||||
let mb_progress = Math.floor(offset / (1024 ** 2))
|
||||
let mb_total = Math.floor(size / (1024 ** 2))
|
||||
status_text.textContent = `Downloading ${filename}... (chunk ${current_chunk}/${chunk_count}, ${mb_progress}/${mb_total}MiB)`;
|
||||
|
||||
let r2 = await fetch(base_url + "/" + chunk);
|
||||
let buffer = await r2.arrayBuffer();
|
||||
let chunk_array = new Uint8Array(buffer);
|
||||
array.set(chunk_array, offset);
|
||||
offset += chunk_array.length;
|
||||
offset += chunk_array.length;
|
||||
current_chunk++;
|
||||
}
|
||||
|
||||
return array.buffer;
|
||||
@ -130,11 +140,12 @@ async function extract_tar(url, fs_path, use_cache = false) {
|
||||
//download tar file from server and decompress
|
||||
let decompressed;
|
||||
if (!use_cache || !await check_db(url)) {
|
||||
let filename = url.split("/").pop();
|
||||
let compressed = await download_chunks(url);
|
||||
decompressed = pako.inflate(compressed);
|
||||
compressed = null;
|
||||
if (use_cache) {
|
||||
console.log("saving to cache");
|
||||
status_text.textContent = `Saving ${filename} to the cache...`;
|
||||
await write_db_chunks(url, decompressed);
|
||||
}
|
||||
}
|
||||
@ -162,11 +173,8 @@ async function extract_tar(url, fs_path, use_cache = false) {
|
||||
}
|
||||
|
||||
async function load_data() {
|
||||
console.log("downloading and extracting game data");
|
||||
await extract_tar("/game/data.tar.gz", "/data", true);
|
||||
console.log("downloading and extracting assets");
|
||||
await extract_tar("/game/assets.tar.gz", "/data", true);
|
||||
console.log("done")
|
||||
}
|
||||
|
||||
async function load_idbfs() {
|
||||
@ -183,28 +191,41 @@ function sync_idbfs(populate = false) {
|
||||
})
|
||||
}
|
||||
|
||||
function wait_for_frame() {
|
||||
return new Promise((resolve) => {requestAnimationFrame(resolve)});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
await load_data();
|
||||
globalThis.ready = true;
|
||||
await load_idbfs();
|
||||
start_button.onclick = () => {requestAnimationFrame(start_game)};
|
||||
start_button.onclick = start_game;
|
||||
start_button.disabled = false;
|
||||
status_text.textContent = "Ready";
|
||||
}
|
||||
|
||||
function start_game() {
|
||||
async function start_game() {
|
||||
status_text.textContent = "Loading game files...";
|
||||
start_button.disabled = true;
|
||||
status_text.textContent = "Initializing";
|
||||
requestAnimationFrame(() => {
|
||||
run();
|
||||
status_text.textContent = "Running";
|
||||
sync_idbfs();
|
||||
});
|
||||
}
|
||||
await load_data();
|
||||
await wait_for_frame();
|
||||
status_text.textContent = "Launching game...";
|
||||
|
||||
globalThis.pako = pako;
|
||||
globalThis.jsUntar = jsUntar;
|
||||
globalThis.load_data = load_data;
|
||||
globalThis.sync_idbfs = sync_idbfs;
|
||||
await wait_for_frame();
|
||||
run();
|
||||
info_container.style.zIndex = 0;
|
||||
info_container.style.display = "none";
|
||||
sync_idbfs();
|
||||
|
||||
console.warn("Warning: Opening devtools may harm the game's performance.");
|
||||
}
|
||||
|
||||
Module["canvas"] = document.getElementById("canvas")
|
||||
main();
|
||||
globalThis.main = main;
|
||||
globalThis.sync_idbfs = sync_idbfs;
|
||||
globalThis.load_idbfs = load_idbfs;
|
||||
|
||||
let poll_runtime_interval = setInterval(() => {
|
||||
if (globalThis.ready) {
|
||||
main();
|
||||
clearInterval(poll_runtime_interval);
|
||||
}
|
||||
}, 100);
|
BIN
wasm/web/supertuxkart_64.png
Normal file
BIN
wasm/web/supertuxkart_64.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
Loading…
Reference in New Issue
Block a user