Initial import.
authorJoe Wreschnig <joe.wreschnig@gmail.com>
Tue, 12 Nov 2013 00:31:32 +0000 (01:31 +0100)
committerJoe Wreschnig <joe.wreschnig@gmail.com>
Tue, 12 Nov 2013 00:31:32 +0000 (01:31 +0100)
index.html [new file with mode: 0644]
o_o.html [new file with mode: 0644]
o_o.js [new file with mode: 0644]
webcart1000.js [new file with mode: 0644]

diff --git a/index.html b/index.html
new file mode 100644 (file)
index 0000000..5acf395
--- /dev/null
@@ -0,0 +1,91 @@
+<html>
+  <head>
+    <title>WEBCART1000</title>
+    <meta charset="utf-8" />
+    <script type="text/javascript" src="webcart1000.js"></script>
+    <style>
+      body {
+      font-family: sans-serif;
+      margin: 1em 15%;
+      }
+
+      h1 { text-align: center; }
+      h2 { margin-top: 2em; }
+    </style>
+       
+  </head>
+  <body>
+    <h1>WEBCART1000</h1>
+    <p>
+      WEBCART1000 lets you make and play games that share the same
+      save files across several websites. It's inspired
+      by <a href="http://sharecart1000.com/">SHARECART10000</a>, which
+      did the same thing for non-web games.
+    </p>
+    <h2>Some Games Using It</h2>
+    <p>
+      coming soon.
+    </p>
+    <h2>How do I use it?</h2>
+    <p>
+      If you're making a web-based game, just
+      download <a href="webcart1000.js">webcart1000.js</a> and include
+      it via a &lt;script&gt; tag in your own game. It's
+      self-contained and sets up all its own listeners.
+    </p>
+    <p>
+      Once you're including it, you can access the save data with
+      <code>webcart1000.data.Whatever</code>
+      - <code>MapY</code>, <code>Switch2</code>, or any of
+      the <a href="http://sharecart1000.com/img/SHARECART1000guide.png">SHARECART1000</a>
+      keys, with the same restrictions. (It may take a few seconds
+      after the page is done loading to load the save data.)
+    </p>
+    <p>
+      To save and synchronize the data,
+      use <code>webcart10000.update()</code>. You can also pass an
+      object of changes, e.g.
+      <code>webcart1000.update({ MapX: 12, MapY: 13, Switch0: false
+      })</code>.  Running <code>update()</code> will also scrub the
+      data so if you put any non-standard keys or values in it,
+      they'll be deleted.
+    </p>
+    <p>
+      If someone's playing two WEBCART1000 games at the same time, the
+      save data is updated in real-time!
+    </p>
+    <h2>Is it safe? Is it private?</h2>
+    <p>
+      Yes.
+    </p>
+    <h3>For Players</h3>
+    <p>
+      There's no cookies. There's no server-mediated
+      messages. Everything WEBCART1000, aside from loading its own
+      static JavaScript, stays on your computer.
+      It's as safe and private as the game would be otherwise.
+    </p>
+    <p>
+      Loading the game leaves at most a default web server log entry -
+      which you've already triggered just by reading this page. Since
+      no data is collected, we don't even have to make a promise we
+      won't share it with anyone - but if we do accidentally collect
+      some, we won't, and we'll just delete it.
+    </p>
+    <h3>For Developers</h3>
+    <p>
+      The provided WEBCART1000 scripts take pains to scrub and
+      normalize the data as much as possible. But this is the web, and
+      they're not served over HTTPS, and people make mistakes. Take
+      the kind of precautions you'd always take in talking to a remote
+      server.
+    </p><p>
+      The <a href="webcart1000.js">webcart1000.js</a> script can be
+      moved to your own server and loaded from there. I recommend this
+      - it'll be faster and stabler. The <a href="o_o.js">o_o.js</a>
+      script and HTML can't be moved unless you're going to make your own
+      WEBCART1000 - which you can if you want, but it also kind of
+      defeats the point.
+    </p>
+  </body>
+</html>
diff --git a/o_o.html b/o_o.html
new file mode 100644 (file)
index 0000000..ccf3518
--- /dev/null
+++ b/o_o.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <title>WEBCART1000</title>
+    <meta charset="utf-8" />
+    <script type="text/javascript" src="o_o.js"></script>
+  </head>
+  <body></body>
+</html>
diff --git a/o_o.js b/o_o.js
new file mode 100644 (file)
index 0000000..061cbb3
--- /dev/null
+++ b/o_o.js
@@ -0,0 +1,71 @@
+(function () {
+    "use strict";
+
+    var broken = false;
+    var _window = window.parent;
+
+    function clamp (i, hi) { return Math.max(0, Math.min(hi, +i | 0)); }
+    function force10 (i) { return clamp(i, 1023); }
+    function force16 (i) { return clamp(i, 65535); }
+    function forcebool (i) { return !!(+i || i === "true"); }
+    function forcestr (s) { return (s || "").toString().substring(0, 1023); }
+
+    var KEYS = {
+        MapX: force10, MapY: force10,
+        PlayerName: forcestr,
+        Misc0: force16, Misc1: force16, Misc2: force16, Misc3: force16,
+        Switch0: forcebool, Switch1: forcebool,
+        Switch2: forcebool, Switch3: forcebool,
+        Switch4: forcebool, Switch5: forcebool,
+        Switch6: forcebool, Switch7: forcebool
+    };
+
+    function generateMessage () {
+        var r = {};
+        for (var k in KEYS)
+            r[k] = KEYS[k](localStorage[k]);
+        return r;
+    }
+
+    function storeMessage (data) {
+        if (!data || typeof data !== "object")
+            return;
+        for (var k in KEYS) {
+            if (k in data) {
+                localStorage[k] = KEYS[k](data[k]);
+            }
+        }
+    }
+
+    function postMessage () {
+        _window.postMessage(generateMessage(), "*");
+    }
+
+    function onMessage (event) {
+        if (broken)
+            return;
+        if (event.data === "refresh") {
+            _window = event.source;
+            postMessage();
+        } else {
+            storeMessage(event.data);
+        }
+    }
+
+    function onStorage (event) {
+        postMessage();
+    }
+
+    window.addEventListener("load", function () {
+        try {
+            localStorage.setItem("WEBCART1000", "WEBCART1000");
+        } catch (exc) {
+            broken = true;
+            return;
+        }
+        window.addEventListener("message", onMessage, false);
+        window.addEventListener("storage", onStorage, false);
+        postMessage();
+    }, false);
+
+}).call(window.webcart1000 = {});
diff --git a/webcart1000.js b/webcart1000.js
new file mode 100644 (file)
index 0000000..5ede7f9
--- /dev/null
@@ -0,0 +1,65 @@
+(function () {
+    "use strict";
+
+    var ORIGIN = "http://yukkurigames.com";
+    var TARGET = ORIGIN + "/webcart1000/o_o.html";
+    var wc1kFrame;
+    var wc1kWindow;
+    var saveData;
+    var _this = this;
+
+    function clamp (i, hi) { return Math.max(0, Math.min(hi, +i | 0)); }
+    function force10 (i) { return clamp(i, 1023); }
+    function force16 (i) { return clamp(i, 65535); }
+    function forcebool (i) { return !!(+i || i === "true"); }
+    function forcestr (s) { return (s || "").toString().substring(0, 1023); }
+
+    var KEYS = {
+        MapX: force10, MapY: force10,
+        PlayerName: forcestr,
+        Misc0: force16, Misc1: force16, Misc2: force16, Misc3: force16,
+        Switch0: forcebool, Switch1: forcebool,
+        Switch2: forcebool, Switch3: forcebool,
+        Switch4: forcebool, Switch5: forcebool,
+        Switch6: forcebool, Switch7: forcebool
+    };
+
+    function scrub (data) {
+        if (typeof data !== "object")
+            data = {};
+        var r = {};
+        for (var k in KEYS)
+            r[k] = KEYS[k](data[k]);
+        return r;
+    }
+
+    function onMessage (event) {
+        if (event.origin !== ORIGIN)
+            return;
+        wc1kWindow = event.source;
+        _this.data = scrub(event.data);
+    }
+
+    function refresh () {
+        wc1kWindow.postMessage("refresh", ORIGIN);
+    }
+
+    function update (data) {
+        for (var k in data)
+            _this.data[k] = data[k];
+        _this.data = scrub(_this.data);
+        wc1kWindow.postMessage(data || _this.data, ORIGIN);
+    }
+
+    window.addEventListener("load", function () {
+        window.addEventListener("message", onMessage, false);
+        wc1kFrame = document.createElement('iframe');
+        wc1kFrame.style.display = "none";
+        wc1kFrame.src = TARGET;
+        document.body.appendChild(wc1kFrame);
+    }, false);
+
+    this.refresh = refresh;
+    this.update = update;
+    this.scrub = scrub;
+}).call(window.webcart1000 = {});