minetest-wasm/static/index.html

233 lines
8.7 KiB
HTML

<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Minetest for the Web</title>
</head>
<body style="background-color: black">
<div id="temporary_console" class="console" style="color: white"></div>
<div id="launch_form" class="console" style="color: white; display: none;">
<hr>
<b>Select Network Proxy:</b>
<select id="select_proxy">
<!-- filled by javascript -->
</select>
<hr>
<button id="launch" style="width: 300px; height: 50px; font-size: 20pt;">Launch Minetest</button>
<br/>
<hr>
<b style="font-size: 20pt;">Run Server In Browser</b>
<br/>
<b>Player Name:</b>
<input style="border: 2px solid black; width: 400px; height: 2em" type="text" id="multiplayer_username" required="" pattern="[A-Za-z0-9_-]{1,20}" maxlength="19" title="Alphanumeric, 19 characters max">
<br/>
<b>Game:</b>
<select id="multiplayer_game">
<option value="minetest_game">minetest_game</option>
</select>
<br/>
<span>After launch, copy the URL and use it to open clients.</span>
<br/>
<span>Closing this page shuts down the server and ends the game.</span>
<br/>
<button id="launch_server" style="width: 300px; height: 50px; font-size: 20pt;">Launch Server</button>
</div>
<div id="join_form" class="console" style="color: white; display: none;">
<b>Joining game:</b>
<br/>
<b>Player Name:</b>
<input style="border: 2px solid black; width: 400px; height: 2em" type="text" id="join_username" required="" pattern="[A-Za-z0-9_-]{1,20}" maxlength="19" title="Alphanumeric, 19 characters max">
<br/>
<button id="join_launch">Join Game</button>
</div>
<script type="text/javascript" src="%__RELEASE_UUID__%/launcher.js"></script>
<script type="text/javascript">
// Reduce memory and network usage
const memorySavingConfig = `
viewing_range = 85
max_block_send_distance = 5
max_block_generate_distance = 5
`;
const launchForm = document.getElementById('launch_form');
const joinForm = document.getElementById('join_form');
const tcon = document.getElementById('temporary_console');
function tcon_print(prefix, line) {
if (prefix) {
for (child of tcon.childNodes) {
if (child.nodeName == 'PRE' && child.innerText.startsWith(prefix)) {
child.innerText = prefix + line;
return;
}
}
}
const p = document.createElement('pre');
p.innerText = prefix + line;
tcon.appendChild(p);
}
function wipePage() {
launchForm.remove();
joinForm.remove();
tcon.remove();
}
function enableLaunchForm() {
if (join_code) {
joinForm.style.display = 'block';
} else {
launchForm.style.display = 'block';
}
const select_proxy = document.getElementById('select_proxy');
const proxies = [
[ "wss://na1.dustlabs.io/mtproxy", "North America" ],
[ "wss://sa1.dustlabs.io/mtproxy", "South America" ],
[ "wss://eu1.dustlabs.io/mtproxy", "Europe" ],
[ "wss://ap1.dustlabs.io/mtproxy", "Asia" ],
[ "wss://ap2.dustlabs.io/mtproxy", "Australia" ],
];
proxies.forEach((entry, index) => {
const opt = document.createElement('option');
opt.value = index;
opt.innerText = entry[1];
select_proxy.appendChild(opt);
});
const launch = document.getElementById('launch');
launch.addEventListener('click', () => {
const proxyIndex = document.getElementById('select_proxy').value;
const proxy = proxies[proxyIndex][0];
wipePage();
mtl.setProxy(proxy);
mtl.launch(args);
});
const launchServer = document.getElementById('launch_server');
launchServer.addEventListener('click', async () => {
const proxyIndex = document.getElementById('select_proxy').value;
const username = document.getElementById('multiplayer_username').value;
const game = document.getElementById('multiplayer_game').value;
if (username.length == 0) {
alert("Empty username");
return;
}
wipePage();
const proxy = proxies[proxyIndex][0];
mtl.setProxy(proxy);
mtl.addPack(game);
const [cmd, serverCode, clientCode] = await queryProxy(`MAKEVPN ${game}`, proxy);
if (cmd != 'NEWVPN') {
alert("Invalid response from proxy");
return;
}
const args = new MinetestArgs();
args.extra.push('--withserver');
args.gameid = game;
args.name = username;
args.address = '127.0.0.1';
args.port = 30000;
args.go = true;
history.pushState({}, "", `?proxy=${proxyIndex}&game=${game}&join=${clientCode}`);
mtl.setVPN(serverCode, clientCode);
mtl.setMinetestConf(memorySavingConfig);
mtl.launch(args);
});
const joinLaunch = document.getElementById('join_launch');
joinLaunch.addEventListener('click', async () => {
const username = document.getElementById('join_username').value;
if (username.length == 0) {
alert("Empty username");
return;
}
wipePage();
mtl.setProxy(proxies[join_proxy][0]);
mtl.addPack(join_game);
const args = new MinetestArgs();
args.gameid = join_game;
args.name = username;
args.address = '172.16.0.1';
args.port = 30000;
args.go = true;
mtl.setVPN(null, join_code);
mtl.setMinetestConf(memorySavingConfig);
mtl.launch(args);
});
}
function queryProxy(cmd, proxy) {
return new Promise((resolve, reject) => {
let finished = false;
const ws = new WebSocket(proxy);
ws.addEventListener('open', (event) => {
ws.send(cmd);
});
ws.addEventListener('error', (event) => {
alert('Error initiating proxy connection');
finished = true;
reject(new Error('Received error'));
});
ws.addEventListener('close', (event) => {
if (!finished) {
alert('Proxy connection closed unexpectedly');
finished = true;
reject(new Error('Received close'));
}
});
ws.addEventListener('message', (event) => {
if (typeof event.data !== 'string') {
alert('Invalid message received from proxy');
finished = true;
reject(new Error('Invalid message'));
return;
}
finished = true;
ws.close();
resolve(event.data.split(' '));
});
});
}
let join_code = null;
let join_proxy = null;
let join_game = null;
const peek_params = new URLSearchParams(window.location.search);
if (peek_params.has("join")) {
join_code = peek_params.get("join");
join_game = peek_params.get("game");
join_proxy = peek_params.get("proxy");
}
const args = MinetestArgs.fromQueryString(window.location.search);
tcon_print("", "Minetest Arguments: " + JSON.stringify(args.toArray(), null, ' '));
tcon_print("", "Data Packs: " + JSON.stringify(args.packs, null, ' '));
const mtl = new MinetestLauncher();
mtl.addPacks(args.packs);
mtl.onprint = (text) => {
tcon_print("", text);
};
mtl.onprogress = (name, progress) => {
const prefix = `Task ${name} : `;
const pct = `${Math.round(progress * 100)}%`;
tcon_print(prefix, pct);
};
mtl.onready = () => {
tcon_print("", "READY!");
enableLaunchForm();
};
mtl.onerror = (err) => {
tcon_print("", "**************** FATAL ERROR ******************");
tcon_print("", err);
tcon_print("", "***********************************************");
};
</script>
</body>
</html>