akashic製ゲームのビジュアルテストツールアップデートとPlaylog

この記事は、Akashic Engine Advent Calendar 2019の23日目の記事です。(インフルエンザを発症してしまった影響で遅刻してしまいました。。)

# はじめに
この前紹介しましたakashic製ゲームのビジュアルテストを行うためのツールをバージョンアップした話をしていきます。今回はツールについて知っていることを前提に説明していきますので、ツールについて知らない方は以下の記事を参照していただければと思います。

- akashic製ゲームのビジュアルテストを行うためのツールを作った話：https://qiita.com/dera_/items/5b6218ea5f6089338877

また、ツール(akashic-contents-reftest-runner)とツールを動かすためのライブラリ(akashic-contents-reftest-helper)のリポジトリは以下の通りです。

- akashic-contents-reftest-runner：https://github.com/dera-/akashic-contents-reftest-runner
- akashic-contents-reftest-helper：https://github.com/dera-/akashic-contents-reftest-helper

# 変更内容と使い方
ゲームを自動実行するためのシナリオを`sandbox.config.js`から取得していましたが、代わりに`playlog.json`というファイルから取得します。
これまでのrunnerでは実行タイミングによってスクリーンショットの取得時に何フレームかずれることもあったのですが、`playlog.json`を利用することによっていつ実行しても同じタイミングでスクリーンショットが取得できるようになりました。

次に新たにアップデートしたrunnerとhelperの利用法についてですが、どちらも以下の方法に従ってインストールしなおします。

- runnerのインストール：https://qiita.com/dera_/items/5b6218ea5f6089338877#%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB
- helperのインストール：https://qiita.com/dera_/items/5b6218ea5f6089338877#akashic-contents-reftest-helper%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB

runnerについては前回の説明と同様に実行することが可能ですが、helperをインストールしたテスト対象のゲームではいくつかの修正が必要になります。
まず、テスト対象のゲームのエントリポイントを以下のように変更します。

```javascript
- var reftestHelper = require("@dera-/akashic-contents-reftest-helper");
- reftestHelper.init(scene); // このファイル中で定義しているsceneを引数として渡す
+ require("@dera-/akashic-contents-reftest-helper");
```

これまではhelperの機能を利用するためにhelperの`init()`を呼び出す必要があったのですが、今回のバージョンアップではそれが不要となりました。

## playlog.jsonの内容
次に、`playlog.json`に記述する内容についてですが、大まかには次のように記述します。

```json
{
    "tickList": [
        0, // 開始フレーム数(number)
        700, // 終了フレーム数(number)
        [
            [0, [Event, ...], null], // 0番目の要素にはフレーム数を、1番目の要素にはその時に起こすEventを記述
            ...
        ]
    ],
    "startPoints": [
        {
            "frame": 0, // 開始フレーム数(number)
            "timestamp": 1575475970578, // 開始unix時間(number)
            "data": {
                "fps": 30,
                "startedAt": 1575475970578
            }
        }
    ]
}
```
このようにゲームの開始フレームから終了フレームまでを定義して、さらにその間に発生するEventを定義することができます。
このデータ構造はゲームの実行ログ(**Playlog**)を表していて、akashic-cli-serveに`--debug-playlog`オプションでこのデータを指定して流すことによって、毎回フレーム単位でPlaylog通りの操作をする様子を映像のようなものとして取得することができます(runnerの新しいバージョンではまさにakashic-cli-serveのこのオプションを利用しています。)。

### Event
ここではEventについての説明をしていきますが、以下の説明は[PlaylogリポジトリのREADME](https://github.com/akashic-games/playlog)からのほぼ抜粋ですので、詳細はそちらを参照してください。
Event はゲーム中で発生する出来事を表すデータで、以下のものを定義することができます。

| EventCode | イベント       |
|:----------|:---------------|
| 0x0       | プレイヤー参加 |
| 0x1       | プレイヤー離脱 |
| 0x2       | 時間の記録     |
| 0x20      | 汎用的なデータ |
| 0x21      | ポイントダウン |
| 0x22      | ポイントムーブ |
| 0x23      | ポイントアップ |
| 0x40      | 操作プラグイン |


Event 共通のデータ・フォーマットは以下のようになります。

| Index | 型     | オプショナル |  説明        |
|:------|:-------|:-------------|:-------------|
| 0     | number | NO           | EventCode    |
| 1     | number | NO           | プライオリティ    |
| 2     | string | NO           | プレイヤーID |

インデックス2番以降は各イベントのデータがセットされます。
以下では、ビジュアルテストのシナリオとして使うことになるであろうEventについて説明していきます。

#### MessageEvent (0x20)

汎用的なデータを表すイベントを表します。

| Index | 型            | オプショナル |  説明            |
|:------|:--------------|:-------------|:-----------------|
| 3     | any           | NO           | 汎用的なデータ   |

ビジュアルテストツールでは、スクリーンショットの取得やゲーム終了といったシナリオ実行のためにこのイベントを使います。
それらシナリオ実行時のデータの型は以下のようになります。

```typescript
{
	type: "scenario";
	command: {
		name: "screenshot" | "finish"; // screenshotでスクリーンショットの取得、finishでゲーム終了
		options?: any; // nameがscreenshotの時、{filename: "出力ファイル名"}を指定する必要があります。nameがfinishの時、何も値を指定する必要はありません。
	};
}
```

#### PointDownEvent (0x21)

ポイントダウンイベントを表します。

| Index | 型            | オプショナル |  説明            |
|:------|:--------------|:-------------|:-----------------|
| 3     | number        | NO           | ポインターID     |
| 4     | number        | NO           | X座標            |
| 5     | number        | NO           | Y座標            |
| 6     | number        | YES          | エンティティID   |

#### PointMoveEvent (0x22)

ポイントムーブイベントを表します。

| Index | 型            | オプショナル |  説明                                       |
|:------|:--------------|:-------------|:--------------------------------------------|
| 3     | number        | NO           | ポインターID                                |
| 4     | number        | NO           | X座標                                       |
| 5     | number        | NO           | Y座標                                       |
| 6     | number        | NO           | ポイントダウンイベントからのX座標の差       |
| 7     | number        | NO           | ポイントダウンイベントからのY座標の差       |
| 8     | number        | NO           | 直前のポイントムーブイベントからのX座標の差 |
| 9     | number        | NO           | 直前のポイントムーブイベントからのY座標の差 |
| 10    | number        | YES          | エンティティID                              |

#### PointUpEvent (0x23)

ポイントアップイベントを表します。

| Index | 型            | オプショナル |  説明                                       |
|:------|:--------------|:-------------|:--------------------------------------------|
| 3     | number        | NO           | ポインターID                                |
| 4     | number        | NO           | X座標                                       |
| 5     | number        | NO           | Y座標                                       |
| 6     | number        | NO           | ポイントダウンイベントからのX座標の差       |
| 7     | number        | NO           | ポイントダウンイベントからのY座標の差       |
| 8     | number        | NO           | 直前のポイントムーブイベントからのX座標の差 |
| 9     | number        | NO           | 直前のポイントムーブイベントからのY座標の差 |
| 10    | number        | YES          | エンティティID                              |

## playlog.jsonをより簡単に取得する方法
ここまでplaylog.jsonの書き方について説明してきましたが、[Akashic Sandbox](https://github.com/akashic-games/akashic-sandbox)という公式で提供されているデバッグツールにPlaylogを取得する機能がありますので、その使い方を説明します。

0. Akashic Sandbox をお使いのPCにインストールしていない場合は`npm install -g @akashic/akashic-sandbox`でインストールします。
1. Playlogを取得したいゲーム上でAkashic Sandboxを起動します。起動方法について詳細は[こちら](https://github.com/akashic-games/akashic-sandbox#%E5%88%A9%E7%94%A8%E6%96%B9%E6%B3%95)を参照してください。
2. Akashic Sandbox起動後、しばらくゲームをプレーします。
3. その後、画面右側の歯車アイコンをクリックして、「Replay」タブを選択して、「今までのリプレイ情報を保存」ボタンを押します。
4. 「保存されているリプレイ情報一覧」に現在のタイムスタンプ名のPlaylogが出現しますので、ファイル出力ボタンで保存します。
5. ファイル名がunixタイム.jsonになっているので、playlog.jsonにリネームしてそのゲームのディレクトリに置いておきます。

ただし、ここで取得できる`playlog.json`にはスクリーンショット取得やゲーム終了といったシナリオ実行のためのMessageEventは一切記載されていないので、直接追記する必要があります。

# まとめ
ここまでアップデートしたrunnerとhelperの利用法と併せてPlaylogについて簡単に説明してきました。
playlog.jsonの記述が若干煩雑ではありますが、Akashic Sandboxを利用することによって比較的容易にplaylog.jsonを生成することもできます(その場合でもスクリーンショットの取得やゲーム終了のためのMessageEventの追記は必要ですが)。
playlog.jsonさえ生成できれば、前バージョンより高精度のテストが可能になるかと思います。