Edited at

あの人気オンラインRPGをハックする

More than 3 years have passed since last update.

70億人近い人間がプレイしている人生というオンラインRPG、

ワールドも無駄に広く建物のモデリングもテクスチャも細かく、

同じ顔のプレイヤーが二人といないほどにキャラメイクが豊富で大変人気のあるゲームです。

ただこのゲーム、現代のゲームに必須なあの機能が実装されていません。

それはデイリーログインボーナスです。


デイリーログインボーナスとは

デイリーログインボーナスとは、プレイヤーに毎日継続してプレイさせるため、

通常有料のアイテムを無料で毎日1つプレゼントする施策です。

現代のゲームの多くは基本的に無料なので、数多ある無料ゲームがユーザの端末と時間を奪い合っていて、ユーザの継続率を上げることは課金につなげる需要要素です。

朝起きれなかったり出勤中に電車に飛び込んだりするのは、すべて人生にログインボーナスが無く、継続のモチベーションが弱いからです。

人生をよりモチベーティブにするためにはログインボーナスが必須なのです。


ログインボーナスを設計する

ログインしたご褒美なので、出勤したらボーナス画像がslackに貼られるというシステムを作ります。

このシステムに必要な機能は以下の4つです。


  • 出勤を判定する

  • ボーナス画像を用意する

  • slackに投稿する

  • 1日に1回だけに制限する


出勤を判定する

出勤すると自動でスマートフォンが会社のWiFiに接続します。

これを判定基準にしたいですよね。

IFTTTには、androidが特定のWiFiに繋がった時に反応するIFレシピがあるのでこれを使います。

DOレシピは単純にSlackにしてしまうと、WiFiに繋がるたびにボーナスが貰えてしまうのでなんとかしないといけません。


ボーナス画像

ボーナス画像には、ニコニコ静画におわす神であるMtU先生デイリーパンツタグが名前の通り最高です。

タグ検索して画像をランダムに1枚取得する機能があればいいですね。

ものすごくググラビリティが低くて探すのに苦労しましたが、niconico コンテンツ検索APIガイドで検索APIが公開されています。

ググって簡単に探せるドキュメントは古く、非常にヤバイ仕様なのですが、最新のAPIは普通にjsonが返ってくるRESTなので使いやすくなっています。

もちろん春画も含めます。


1日に1回だけにする

1日1回だけ何かをするようなWebAPIは探してみたけど見つかりませんでした。

この部分はAPIを自作しないといけないようです。

というわけで出勤判定のDOレシピは、Makerを使ってこのAPIにWebhookを送ります。

Webhookを受け取って、それが1日の最初のアクセスだった場合にSlackに投稿します。


Slackに投稿する

SlackにはOAuth APIが用意されているのでこれを使います。

ということは認証フローのためにAPIだけでなくWebページも必要になりました。


まとめると、SlackでOAuthするためのフロントページとWebhookを受け取ってSlackに投稿するAPIを作ればよさそうです。

Railsなら数十分くらいで作れそうですが、デプロイと運用が面倒です。

サーバなんか持ちたくないしPaaSすら面倒くさい、なぜならサーバはいつか死ぬしプロセスもいつか死ぬから。

なのでそういう面倒くささを避けるために、APIはAPI Gateway + AWS Lambdaで、フロントページはAmazon S3の静的ページホスティングで配信することにしました。

そうなると全部js、あまりjs書いたこと無いので結構なチャレンジです。


実装する

masarakki/daily-login-bonus

特に難しいコードではないのでポイントだけ挙げます。


フロント

SPAでOAuthどうやんのって長いこと悩んでいましたが、redirect_uriに自分自身を指定し、

?code=xxxがついてたらアクセストークンを貰いに行くという方法で十分だったんですねぇ。

アクセストークンを取得するところで、app_secretが必要なのですが、一応secretなので隠したほうが良さそうです。

なのでAPI GatewayのWebProxy機能を使ってパラメータにapp_secretの値を追加しようと思ったんですが、WebProxyはリクエストのパラメータ名を変えたりできるだけで、任意の値のパラメータを追加することはできないようです。

仕方がないのでトークン取得APIもバックエンドはAWS Lambdaにせざるをえませんでした。


AWS Lambda

複数のLambdaを管理するのは面倒なので、トークン取得もWebhookのCRUDもひとつのLambdaにぶち込めるようにしました。

Railsを参考に、Lambdaの入力(json)にcontrolleractionを指定することでルーティングします。

見つけたメソッドにparamsで指定したデータを処理させます。

入力はこんな感じになります

{

"controller": "webhook",
"action": "update",
"params": {
"key1": "xyz",
"key2": 123
}
}

ビルドにはlambda_packageを使いました。

フロントのjsも同じリポジトリで管理するので、そのままビルドするとフロントで使うライブラリも入ってしまいます。

ダミーのlambda/package.jsonを置き、オプションでディレクトリ指定する必要があります。


API Gateway

APIの構造はこんな感じです。

とにかくドキュメントがわかりにくすぎてつらかった・・・

すべてのエンドポイントのmapping templateにcontrolleractionを指定するのが本当にクソだるかったんですが、なんか良い方法あるんですかね。

それとも 1 エンドポイント <=> 1 Lambda にするのが普通なんでしょうか。


使ってみる

http://daily-login-bonus.s3-website-ap-northeast-1.amazonaws.com/

Slack認証してチャンネルを選んでcreateするとWebhookのエンドポイントが発行されます。

Webhookに送るjsonデータでSlackの投稿内容を編集できます。

{

"message": "@masarakki 今日もがんばって出社して偉いじゃない! ご褒美をあげるわ!",
"name": "駆逐艦 雷",
"icon": ":ikazuchi:"
}

WiFiに繋がるとこんなご褒美が貰えます。

あぁ・・・尊い・・・

js慣れてないしLambda初めてなのでここまで作るのにだいたい3日くらいかかりました。

しかしサーバのこと考えずにAPI作れてLambdaとAPI Gatewayほんとすごい。


感想

1日1回を判定するAPIと静画から画像を取ってくるAPIを独立させて、

全部Webhookで繋いだほうが良かったのかなぁと迷ってます。

Slack投稿はifttt任せで。

Webhookが増えすぎるのが面倒で避けたかったんですが、どちらが良かったんだろうか。

初めて最近のjsっぽいプログラミングしたんですが、browserifyでまとめられたjsってデバッグしにくくないですか?

いろいろ言われてるけど開発中に限って言えばsprockets最高だなと思いました。

あと本気でjsやらないと3年後には仕事がないと思いました。


追記

タグを拾ってきているだけなのでたまにこういうことが起こります