RPGアツマールのユーザーシグナルでいいね！を送る

# 概要

RPGアツマールには非同期ネットゲームを想定したAPIが存在します
その中の「ユーザーシグナル」を使ってみた記事です

ユーザーを指定して:thumbsup:いいね！:thumbsup:を送ってみました

# 作ったもの

* 最近遊んだユーザー一覧を取得して指定したユーザーにいいね！を送る
  * https://game.nicovideo.jp/atsumaru/games/gm9445 (Ver1.4から)

# シグナルとは

ユーザー間での情報のやり取りを、シグナルという機能によって行えます
シグナルには100byte以内の情報(文字列)を入れることができます

例えば、送り側で以下のようなjsonの文字列を作って送信します

```javascript
{ SignalId:1, SaveIdx:1, GoodId:2 }
```

受け側ではシグナルを取得すると送られた上記の文字列を取得できます
jsonを解釈することで、送り側から送られたSignalIdとSaveIdxとGoodIdの値が分かるという流れです

送り側のユーザーIDや名前はこれとは別に付与されているので含めなくて大丈夫です

## ユーザーシグナルの動き

ユーザーIDを指定して特定のユーザーに向けて送る
「ユーザーシグナル」の動きを解説します

送り側は
`window.RPGAtsumaru.experimental.signal.sendSignalToUser()`
を実行します

送り側と受け側がいて
<img width="400" alt="図1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107395/21048ace-4e22-d036-dad7-f38edd853ade.png">

1件送るとこうなって・・・
<img width="400" alt="図2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107395/ded6d222-c523-0384-738e-b2db2cd6d7c6.png">

また1件送るとこうなって・・・
<img width="400" alt="図3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107395/487cd7a5-9d77-8084-f65d-80a37e690e4e.png">

サーバーに蓄積されていくイメージです

受け側は
`window.RPGAtsumaru.experimental.signal.getUserSignals()`
を実行します

1回の実行で先程送られた2件を全部取得します
<img width="400" alt="図3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107395/a00d3d4f-91df-079e-b8d8-9f0bde2c2acd.png">


またこの後に、送り側から3件目、4件目を送信してから、
受け側でシグナルの取得を行うと、受け側では1~4件目を全部取得してしまいます

APIの実行では全部取得してしまうので、
ゲーム側で新しいシグナルだけを読みたい場合は、
どこまで取得したかの情報をクライアントで持っておく必要があります

公式プラグインの`AtsumaruUserSignalExperimental.js`が、
この辺りの制御をうまくやっていて、全シグナルを取りつつ、
ゲーム側には新しいシグナルしか渡さないようになっています

## 公式プラグインを読み解く

`AtsumaruUserSignalExperimental.js`を読み解いてみます
使う人が知っていればいい情報を書いておきます

* プラグインコマンド
   * SendUserSignal
      * ユーザーシグナルを送信します。通常は`$gameVariables`の変数を送るようになっていますが`Json.stringify`で文字列を作るような改造をしてしまった方が使い勝手がよいです
   * GetUserSignal
      * 1回の実行で1件のシグナルを処理します
      * サーバーから取得したシグナル全件をローカルでためておきます。それを順に読んでいます。
      * ローカルで持っているシグナルが0件になったら`fetchUserSignal`が実行され、`setUserSignal`で`$gameVariables`にセットされます
      * SendUserSignalの実装をJsonを送るように変えていたら、`setUserSignal`の方はJsonを解釈するように改造しておきます

* どこまで読んだかの制御について
   * 知らなくてもよいですがプラグインの中身はこうなっていました
   * `$gameSystem`の中に、`$gameSystem._userSignalStoreForRPGAtsumaruPlugin.lastPoppedSignals`というメンバが増えています
   * 最後に取得したシグナルがここに入っているため、以降の`getUserSignals()`の実行では、`lastPoppedSignals`に保存されているシグナルの`createdAt`を見て、どこまでをゲーム側に渡すかを制御しています
   * `$gameSystem`の中に定義されたものなので、最後に取得したシグナルの情報はセーブデータにも入ります
   * これにより続きから始めたときでも新しいものしか取得しないようになっています

## 全てのシグナルを取得できない可能性がある

以下のことに注意してゲームの仕様を決める必要があります

* 一定の件数/容量を超えると古いものから削除される仕様のためシグナルは全て受け取れない可能性がある
* 件数や容量の詳細は公式の制限詳細を参照してください
   * https://atsumaru.github.io/api-references/signal

# 「いいね！を送る」を実装する

「送り側」と「受け側」の実装に分けて説明します

## 送り側

こういうjsonを作って送ります

```javascript
{ 
   SignalId:1, // ゲーム側で定義するシグナルの種類
   SaveIdx:1,  // セーブデータ番号
   GoodId:2    // GoodId
}
```

* `SignalId`
   * 「シグナルの種類」が入っています
   * いいねシグナルは1、ログイン通知シグナルは2を入れて・・・といった感じにゲームの方で定義しています
* `SaveIdx`
   * 受け側の「セーブデータの番号」です
   * 複数のセーブデータがあるとどのセーブデータでも受け取ってしまうのでそれを判別できるようにする必要があったので付与しました
* `GoodId`
   * いいねシグナル固有の情報です
   * いいね！だったら1、すごいね！だったら2、サイコーだね！だったら3・・・といった感じにゲームの方で定義しています

これを`JSON.stringfy`で文字列にして`window.RPGAtsumaru.experimental.signal.sendSignalToUser()`で送ります

また、短時間にシグナルを送信しすぎるとAPIの制限に引っかかるので注意してイベントを組むようにします。いいね！送信のイベントの後に意図的に数秒のウエイトを入れています(演出でごまかすなりした方がユーザー体験は良いかも)

秒数の制限については公式の説明を参照してください
→ https://atsumaru.github.io/api-references/common/rate-limit

## 受け側

受け側は`window.RPGAtsumaru.experimental.signal.getUserSignals()`で受け取ります

`setUserSignal()`の引数の`store`が持っている`signals`(→`store.signals`でアクセス)
にシグナルのデータが配列で入っています
`pop()`してやると1件分のシグナルが取り出せます

```javascript
createdAt: 1559966464
data: "{"SignalId":1,"SaveIdx":1,"GoodId":2}"
id: 1234567
senderId: 9876543
senderName: "Shirogane"
```

送り側のユーザーIDや名前も付与された状態で取り出せます
送り側が作ったデータは`data`の中にあります

* 送り側からはJsonを送るようにしてあるので`Json.parse`で`signal.data`をオブジェクトに直す
* セーブデータ番号 `SaveIdx` が今のセーブ番号と一致している場合だけ処理する
* `SignalId`が1だったら、いいねシグナルとして処理をする
* `GoodId`が2なので「すごいね！」が送られたものとして処理をする

これらを使って、
イベント側で通知のプラグインなどを使って以下のような通知を出してみます

<img width="500" alt="図5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107395/29cb87cd-01fc-29b7-df8f-6e5817f3257a.png">

# まとめ

シグナルの仕組みの説明と、それを使って:thumbsup:いいね！:thumbsup:を送る実装を行いました
グローバルシグナルもほぼ同じはずなので同じように実装できると思います