2016-03-12 13:50:43 -05:00
|
|
|
"use strict";
|
|
|
|
|
2016-04-30 06:50:43 -04:00
|
|
|
//! {"description": "Massively multiplayer online Turtle Graphics"}
|
|
|
|
|
2016-03-12 13:50:43 -05:00
|
|
|
// This script runs server-side, once for each client session.
|
|
|
|
|
|
|
|
if (imports.terminal) {
|
|
|
|
terminal.setEcho(false);
|
|
|
|
terminal.split([
|
2016-04-04 16:26:01 -04:00
|
|
|
{
|
|
|
|
type: "horizontal",
|
|
|
|
children: [
|
|
|
|
{name: "graphics", basis: "700px", shrink: "0", grow: "0"},
|
|
|
|
{name: "text"},
|
|
|
|
],
|
|
|
|
},
|
2016-03-12 13:50:43 -05:00
|
|
|
]);
|
|
|
|
|
|
|
|
// Request a callback every time the user hits enter at the terminal prompt.
|
|
|
|
core.register("onInput", function(input) {
|
|
|
|
// Ask a persistent service session to broadcast our message. We'll also get a copy back.
|
|
|
|
return core.getService("turtle").then(function(service) {
|
|
|
|
return service.postMessage(input);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
// Request a callback for every message that is broadcast.
|
|
|
|
core.register("onMessage", function(sender, message) {
|
|
|
|
if (message.history) {
|
|
|
|
for (var i = 0; i < message.history.length; i++) {
|
|
|
|
// Pass the message on to the iframe in the client.
|
|
|
|
terminal.postMessageToIframe("turtle", message.history[i]);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Pass the message on to the iframe in the client.
|
|
|
|
terminal.postMessageToIframe("turtle", message);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
core.register("onWindowMessage", function(data) {
|
2016-04-04 16:26:01 -04:00
|
|
|
if (data.message.ready) {
|
|
|
|
core.getService("turtle").then(function(service) {
|
|
|
|
return service.postMessage("sync");
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
terminal.print(data.message);
|
|
|
|
}
|
2016-03-12 13:50:43 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
terminal.select("graphics");
|
|
|
|
terminal.print("MMO Turtle Graphics using ", {href: "http://codeheartjs.com/turtle/"}, ".");
|
|
|
|
|
|
|
|
// Add an iframe to the terminal. This is how we sandbox code running on the client.
|
|
|
|
var contents = `
|
2016-04-04 16:26:01 -04:00
|
|
|
<script src="https://codeheart.williams.edu/turtle/turtle.min.js">-*- javascript -*-</script>
|
2016-03-12 13:50:43 -05:00
|
|
|
<script>
|
|
|
|
setScale(2);
|
|
|
|
setWidth(3);
|
|
|
|
|
|
|
|
// Receive messages in the iframe and use them to draw.
|
|
|
|
function onMessage(event) {
|
|
|
|
var parts = event.data.split(" ");
|
|
|
|
var command = parts.shift();
|
|
|
|
if (command == "reset") {
|
|
|
|
setPosition(0, 0);
|
|
|
|
setHeading(0);
|
|
|
|
clear(WHITE);
|
|
|
|
_ch_startTimer(30);
|
|
|
|
} else if (command == "home") {
|
|
|
|
var wasDown = _turtle.penDown;
|
|
|
|
pu();
|
|
|
|
setPosition(0, 0);
|
|
|
|
setHeading(0);
|
|
|
|
if (wasDown) {
|
|
|
|
pd();
|
|
|
|
}
|
|
|
|
_ch_startTimer(30);
|
|
|
|
} else if (command == "clear") {
|
|
|
|
clear(WHITE);
|
|
|
|
_ch_startTimer(30);
|
2016-04-04 16:26:01 -04:00
|
|
|
} else if (["fd", "bk", "rt", "lt", "pu", "pd", "setColor", "setWidth"].indexOf(command) != -1) {
|
|
|
|
window[command].apply(window, parts.map(parseFloat));
|
2016-03-12 13:50:43 -05:00
|
|
|
event.source.postMessage(event.data, event.origin);
|
|
|
|
_ch_startTimer(30);
|
|
|
|
} else {
|
|
|
|
event.source.postMessage("Unrecognized command: " + command, event.origin);
|
|
|
|
}
|
2016-04-04 16:26:01 -04:00
|
|
|
if (_turtle.nextCommandIndex >= _turtle.commandBuffer.length) {
|
|
|
|
_turtle.nextCommandIndex = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function onLoad() {
|
|
|
|
parent.postMessage({ready: true}, "*");
|
2016-03-12 13:50:43 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Register for messages in the iframe
|
|
|
|
window.addEventListener('message', onMessage, false);
|
2016-04-04 16:26:01 -04:00
|
|
|
|
|
|
|
window.addEventListener('load', onLoad, false);
|
2016-03-12 13:50:43 -05:00
|
|
|
</script>
|
|
|
|
`
|
|
|
|
terminal.print({iframe: contents, width: 640, height: 480, name: "turtle"});
|
|
|
|
|
|
|
|
terminal.select("text");
|
|
|
|
terminal.print("Supported commands: ", ["fd <distance>", "bk <distance>", "rt <angle>", "lt <angle>", "pu", "pd", "home", "reset", "clear"].join(", "));
|
|
|
|
} else {
|
|
|
|
var gHistory = null;
|
|
|
|
|
|
|
|
function ensureHistoryLoaded() {
|
|
|
|
if (!gHistory) {
|
|
|
|
return database.get("history").then(function(data) {
|
|
|
|
gHistory = JSON.parse(data);
|
|
|
|
return gHistory;
|
|
|
|
}).catch(function(error) {
|
|
|
|
gHistory = [];
|
|
|
|
return gHistory;
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
return new Promise(function(resolve, reject) { resolve(gHistory); });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
core.register("onMessage", function(sender, message) {
|
|
|
|
return ensureHistoryLoaded().then(function(history) {
|
|
|
|
if (message == "reset") {
|
|
|
|
history.length = 0;
|
|
|
|
database.set("history", JSON.stringify(history));
|
|
|
|
return core.broadcast(message);
|
|
|
|
} else if (message == "sync") {
|
|
|
|
sender.postMessage({history: history});
|
|
|
|
} else {
|
|
|
|
history.push(message);
|
|
|
|
database.set("history", JSON.stringify(history));
|
|
|
|
return core.broadcast(message);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|