You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
169 lines
4.8 KiB
169 lines
4.8 KiB
var channelHandlers = {} |
|
|
|
function addSimMessageHandler(channel, handler) { |
|
channelHandlers[channel] = handler; |
|
} |
|
|
|
function makeCodeRun(options) { |
|
var code = ""; |
|
var isReady = false; |
|
var simState = {} |
|
var simStateChanged = false |
|
var started = false; |
|
var meta = undefined; |
|
|
|
// hide scrollbar |
|
window.scrollTo(0, 1); |
|
// init runtime |
|
initSimState(); |
|
fetchCode(); |
|
|
|
// helpers |
|
function fetchCode() { |
|
sendReq(options.js, function (c, status) { |
|
if (status != 200) |
|
return; |
|
code = c; |
|
// find metadata |
|
code.replace(/^\/\/\s+meta=([^\n]+)\n/m, function (m, metasrc) { |
|
meta = JSON.parse(metasrc); |
|
}) |
|
var vel = document.getElementById("version"); |
|
if (meta.version && meta.repo && vel) { |
|
var ap = document.createElement("a"); |
|
ap.download = "arcade.uf2"; |
|
ap.href = "https://github.com/" + meta.repo + "/releases/download/v" + meta.version + "/arcade.uf2"; |
|
ap.innerText = "v" + meta.version; |
|
vel.appendChild(ap); |
|
} |
|
// load simulator with correct version |
|
document.getElementById("simframe") |
|
.setAttribute("src", meta.simUrl); |
|
initFullScreen(); |
|
}) |
|
} |
|
|
|
function startSim() { |
|
if (!code || !isReady || started) |
|
return |
|
setState("run"); |
|
started = true; |
|
const runMsg = { |
|
type: "run", |
|
parts: [], |
|
code: code, |
|
partDefinitions: {}, |
|
cdnUrl: meta.cdnUrl, |
|
version: meta.target, |
|
storedState: simState, |
|
frameCounter: 1, |
|
options: { |
|
"theme": "green", |
|
"player": "" |
|
}, |
|
id: "green-" + Math.random() |
|
} |
|
postMessage(runMsg); |
|
} |
|
|
|
function stopSim() { |
|
setState("stopped"); |
|
postMessage({ |
|
type: "stop" |
|
}); |
|
started = false; |
|
} |
|
|
|
window.addEventListener('message', function (ev) { |
|
var d = ev.data |
|
if (d.type == "ready") { |
|
var loader = document.getElementById("loader"); |
|
if (loader) |
|
loader.remove(); |
|
isReady = true; |
|
startSim(); |
|
} else if (d.type == "simulator") { |
|
switch (d.command) { |
|
case "restart": |
|
stopSim(); |
|
startSim(); |
|
break; |
|
case "setstate": |
|
if (d.stateValue === null) |
|
delete simState[d.stateKey]; |
|
else |
|
simState[d.stateKey] = d.stateValue; |
|
simStateChanged = true; |
|
break; |
|
} |
|
} else if (d.type === "messagepacket" && d.channel) { |
|
const handler = channelHandlers[d.channel] |
|
if (handler) { |
|
try { |
|
const buf = d.data; |
|
const str = uint8ArrayToString(buf); |
|
const data = JSON.parse(str) |
|
handler(data); |
|
} catch (e) { |
|
console.log(`invalid simmessage`) |
|
console.log(e) |
|
} |
|
} |
|
} |
|
}, false); |
|
|
|
// helpers |
|
function uint8ArrayToString(input) { |
|
let len = input.length; |
|
let res = "" |
|
for (let i = 0; i < len; ++i) |
|
res += String.fromCharCode(input[i]); |
|
return res; |
|
} |
|
|
|
function setState(st) { |
|
var r = document.getElementById("root"); |
|
if (r) |
|
r.setAttribute("data-state", st); |
|
} |
|
|
|
function postMessage(msg) { |
|
const frame = document.getElementById("simframe"); |
|
if (frame) |
|
frame.contentWindow.postMessage(msg, meta.simUrl); |
|
} |
|
|
|
function sendReq(url, cb) { |
|
var xhttp = new XMLHttpRequest(); |
|
xhttp.onreadystatechange = function () { |
|
if (xhttp.readyState == 4) { |
|
cb(xhttp.responseText, xhttp.status) |
|
} |
|
}; |
|
xhttp.open("GET", url, true); |
|
xhttp.send(); |
|
} |
|
|
|
function initSimState() { |
|
try { |
|
simState = JSON.parse(localStorage["simstate"]) |
|
} catch (e) { |
|
simState = {} |
|
} |
|
setInterval(function () { |
|
if (simStateChanged) |
|
localStorage["simstate"] = JSON.stringify(simState) |
|
simStateChanged = false |
|
}, 200) |
|
} |
|
|
|
function initFullScreen() { |
|
var sim = document.getElementById("simframe"); |
|
var fs = document.getElementById("fullscreen"); |
|
if (fs && sim.requestFullscreen) { |
|
fs.onclick = function() { sim.requestFullscreen(); } |
|
} else if (fs) { |
|
fs.remove(); |
|
} |
|
} |
|
} |