RPG アツマールに RPG ツクール MV 製ではないゲームをアップする

この記事は [RPG ツクール MV Advent Calendar 2016](http://www.adventar.org/calendars/1732)の 25 日目の記事です。メリークリスマス!

# tl;dr (要約)

[RPG アツマール](http://game.nicovideo.jp/atsumaru/)は RPG ツクール MV 製のゲームがアップできるサイトです。 RPG ツクール MV のゲームは純粋な Web アプリケーションであるが故に、アツマールに RPG ツクール MV とは無関係の Web アプリケーションをアップすることが出来ます。アツマールには RPG ツクール MV のゲームを想定した制約が幾つかあり、その制約を守る必要があります。 JavaScript のファイルサイズについても制約に引っかかる可能性がありますが、 lz-string.js による圧縮で工夫して乗り切れます。

# RPG アツマールと RPG ツクール MV

[RPG アツマール](http://game.nicovideo.jp/atsumaru/)は RPG ツクール MV 製のゲームがアップできるサイトです。

一方 RPG ツクール MV は PC 版における RPG ツクールの最新作です。エディタはネイティブですが、ゲームは純粋な Web アプリケーションです。ゲームのロジックはすべて JavaScript で記述されており、公開されています。ちなみにゲームデータ自体は JSON であり、エディタは高級 JSON 編集ソフトとみなすことができます。

さて、アツマールはツクール MV のゲームを投稿できるサイトですが、果たしてツクール MV とは関係なく生成した Web アプリケーションをアップすることはできるのでしょうか? 結論から言うと条件付きで可能です。アツマールは ツクール MV 製のゲームを想定した制約が幾つかあり、その制約の範囲内でなら任意の JavaScript ゲームをアップすることが可能です。

# 具体例

筆者が実際に作った (というよりは移植した) ゲームとして「[いの べーしょん 2007](http://game.nicovideo.jp/atsumaru/games/gm88)」があります。これは Go で書かれていたものを [GopherJS](http://www.gopherjs.org/) によって JavaScript に変換したもので、 RPG ツクール MV とは全く無関係です。

![game1.png](https://qiita-image-store.s3.amazonaws.com/0/1911/48d0dd45-6692-7339-4683-33b3575880b5.png)

巨大な JavaScript ファイルを読み込むため若干実行に時間がかかります。スマートフォンでも PC モードにすれば一応動くようです。

RPG ツクール MV のために用意されている機能は一部機能しません。たとえば、ツクール MV のために用意された仮想パッドやオンラインセーブは全く機能していません。コメントは打てますが、最初の画面にすべて書かれるようです。

# アツマールの制約

アツマールにアップする制約に関しては、以下のページが参考になります:

* [[RPGアツマール]ゲームの投稿・更新・削除について | ニコニコヘルプ](http://qa.nicovideo.jp/faq/show/6576)
* [【仕様】RPGアツマールのセキュリティ上の制限について:ニコニコ自作ゲームフェス:ニコニコ自作ゲームフェス(ニコニコ自作ゲームフェス) - ニコニコチャンネル:ゲーム](http://ch.nicovideo.jp/indies-game/blomaga/ar1152126)

要約すると次のとおりです。なお条件はいつでも変更される可能性があります:

* 条件によっては index.html が上書きされる (ヘルプだと無条件で index.html が書き換わると書かれているように見えるが、実際のところそうではなく、一定の条件下のみで上書きされる。運営に確認済み)。また、 index.html に対してコメント用の CSS のための要素が挿入される。
* 拡張子はホワイトリスト方式で、リストにない拡張子のファイルはアップできない。ファイルの中身もある程度精査される。
* [CSP](https://developer.mozilla.org/ja/docs/Web/Security/CSP) による制限があり、 `html5.nicogame.jp` 以外のドメインとは通信できない。

index.html の上書き条件についてはわかりませんが、少なくとも以下のような単純なものだと上書きされないようです:

```html:index.html
<!DOCTYPE html>
<script src="lz-string.js"></script>
<script src="main.js"></script>
```

HTML ファイル内にインラインで JavaScript を書いてはいけないようなので、別ファイルで JavaScript を用意してやればよいです。

以上、基本的には「制約を守ってゲームを作れば良し」で終わりなのですが、筆者の場合は「JavaScript ファイルが大きすぎる」という問題にひっかかってしまいました。以下はその対処方法について述べます。

# JavaScript が大きすぎる場合

ヘルプによると JavaScript のファイルサイズ上限は 5MB とのことですが、ミニマイズしても 5MB を超えてしまう場合はどうしたらよいでしょうか。ファイルを分割してもいいのですが、それも困難な場合どうしたらよいでしょうか。

せっかくなのでツクール MV のゲームにも使われている lz-string.js[^1] を利用してやりましょう。 [Node.js](https://nodejs.org/) を利用して、コンソール上で圧縮した JavaScript ファイルをつくってあげます。指定したファイルを圧縮するプログラムは次の通り:

[^1]: [lz-string](https://github.com/pieroxy/lz-string)。ライセンスは WTFPL なので、パブリックドメインとほぼ同じく、ライセンス表記等は特に気にしなくてよいようです。

```js:compress.js
var lz = require('./lz-string.js');
var fs = require('fs')
var argv = process.argv;
var data = fs.readFileSync(argv[2], { encoding: 'utf8' });
var compressed = lz.compressToBase64(data);
fs.writeFileSync(argv[3], compressed)
```

これをターミナル上で node コマンドで次のように実行すれば、圧縮された JavaScript が生成されます。 lz-string.js は同じディレクトリに置いておく必要があります:

```shell-session
node compress.js yourgame.js yourgame.compressed.js
```

「いの べーしょん 2007」の場合は、ファイルサイズは次のようになりました:

||サイズ|
|:-:|:-:|
|圧縮前|5145540[bytes]|
|圧縮後 (BASE64 形式)|1964632[bytes]|

実際に圧縮した yourgame.compressed.js を実行する main.js は次のようになります。 XHR で取得した文字列を展開し、 eval で実行してあげるだけです:

```js:main.js
'use strict';

(function() {
    var path = './yourgame.compressed.js';
    var req = new XMLHttpRequest();
    req.open('GET', path, true);
    req.responseType = 'text';
    req.onload = function() {
        var status = req.status;
        if (status === 200) {
            var script = LZString.decompressFromBase64(req.response);
            // グローバルスコープで実行するために、 eval を間接参照する。
            // 参考: http://qiita.com/SFPGMR/items/7a09507eead5b5db8d17
            (0, eval)(script);
            return
        }
        console.error('status error:', status);
    };
    req.onerror = function() {
        console.error('XMLHttpRequestError:', req.statusText);
    };
    req.send();
})();
```

HTML ファイルは次のようにします。 lz-string.js はツクール MV に付属しているものです:

```html:index.html
<!DOCTYPE html>
<script src="lz-string.js"></script>
<script src="main.js"></script>
```

ローカルのブラウザで動作確認してみてください。 `file://` からはじまる URL だと恐らく Cross Origin 関係のエラーが出ると思われるので、ローカルで簡単な HTTP サーバーを立ち上げて `http://localhost...` な URL で実行すると良いです。筆者は Python のワンライナーをよく使います:

```shell-session
python -m SimpleHTTPServer 8000
```

あとは `main.js`、 `lz-string.js`、 `yourgame.compressed.js`、 `index.html` を一つのディレクトリにして zip 圧縮し、アツマールに投稿してあげればよいです。