これは、皆さん分かってると思いますが achievement というひとつのmikutterプラグインが提供している機能で、 achievement APIを使えば他のプラグインから実績を新しく追加することができます。
どんな風に実績を追加するか、実際のコードを見てみましょう。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Plugin.create :twihai_achievements do | |
defachievement(:red_fav, | |
description: "1つのツイートに5ふぁぼ以上された", | |
hint: "おもしろツイートで5fav以上もらおう" | |
) do |achievement| | |
on_favorite do |service, user, message| | |
if message.user.is_me? and message.favorited_by.size >= 5 | |
achievement.take! end end end | |
end |
defacievement
実装についてもう少し詳しく見てみましょう。defacievementというプラグインメソッドが今回の肝です。
第一引数はスラッグ、第二引数には以下の値を指定します。
- description ... 説明。現在は見返す方法がないので、用意されているだけ
- hint ... 起動時にアクティビティに表示されるヒント。hiddenがtrueなら必要ない
- depends ... 前提実績。実績のスラッグをシンボルの配列で指定する。指定された全ての実績が解除されていないとヒントが表示されない。
- hidden ... 隠し実績。trueなら、起動時にランダムに表示されるヒントの抽選対象に入れない。
defacievement のブロック
ここには実績を解除するための条件を記述します。このブロック、そもそも実績が解除された状態では実行されません。解除するための条件なので、もう解除された状態では必要がないのです。
この例では、「on_favorite ...」という部分です。この中もプラグインの一部なので、こうやってイベントリスナを設定することができるのです。
Plugin::Achievement::Achievement
defachievement ブロックは一つの引数を取ります。これは実績オブジェクト(Plugin::Achievement::Achievement)のインスタンスです。実績の主要な情報を得たり、実績を解除するために使います。defachievementを呼び出す度にインスタンスが一つ作られる感じで、普段あまり気にするものではないです。
実績解除
Plugin::Achievement::Achievement#take! を呼びだせば実績が解除されます。このメソッドが呼ばれると、直ちに defachievement ブロック内でセットされたイベントリスナやフィルタ(例ではon_favorite)が解除されます。
それから、前提実績をチェックして、まだ解除されていないものがあればそれを待ちます。これは、前提となる実績より先に現在の実績が解除されるのを防ぐためです。この状態で前提実績が解除されたら、すぐにこの実績も解除されます。
そうやって実際に解除されたら、 achievement_took イベントが発火されます。
achievement_took(Plugin::Achievement::Achievement)
実績解除のメッセージはこのイベントをachievementプラグインが受け取った時に表示されるようになっています。実績解除をトリガーに何かをしたいということはあまり無さそうですが。
実績の例
mikutterの標準の実績は全て achievement プラグインに集約されています。以下のプラグインの100行目あたりから後は、全て実績の定義です。
http://dev.mikutter.hachune.net/projects/mikutter/repository/revisions/develop/entry/core/plugin/achievement/achievement.rb
実績を見てしまうとネタバレになるのですが、それぞれが全く異なった方法で実装されているので、これだけで例としては十分でしょう。このファイルの前半の方は、実績プラグイン自信の実装です。このプラグイン、mikutterプラグインとしても結構興味深いのですが、それについては別の機会に触れたいと思います。
ヒントのタイミング
最後に、一応、実績のヒント(hint)がユーザに提示される条件を説明しておきます。毎回mikutterが起動される度に、
ここには実績を解除するための条件を記述します。このブロック、そもそも実績が解除された状態では実行されません。解除するための条件なので、もう解除された状態では必要がないのです。
この例では、「on_favorite ...」という部分です。この中もプラグインの一部なので、こうやってイベントリスナを設定することができるのです。
Plugin::Achievement::Achievement
defachievement ブロックは一つの引数を取ります。これは実績オブジェクト(Plugin::Achievement::Achievement)のインスタンスです。実績の主要な情報を得たり、実績を解除するために使います。defachievementを呼び出す度にインスタンスが一つ作られる感じで、普段あまり気にするものではないです。
実績解除
Plugin::Achievement::Achievement#take! を呼びだせば実績が解除されます。このメソッドが呼ばれると、直ちに defachievement ブロック内でセットされたイベントリスナやフィルタ(例ではon_favorite)が解除されます。
それから、前提実績をチェックして、まだ解除されていないものがあればそれを待ちます。これは、前提となる実績より先に現在の実績が解除されるのを防ぐためです。この状態で前提実績が解除されたら、すぐにこの実績も解除されます。
そうやって実際に解除されたら、 achievement_took イベントが発火されます。
achievement_took(Plugin::Achievement::Achievement)
実績解除のメッセージはこのイベントをachievementプラグインが受け取った時に表示されるようになっています。実績解除をトリガーに何かをしたいということはあまり無さそうですが。
実績の例
mikutterの標準の実績は全て achievement プラグインに集約されています。以下のプラグインの100行目あたりから後は、全て実績の定義です。
http://dev.mikutter.hachune.net/projects/mikutter/repository/revisions/develop/entry/core/plugin/achievement/achievement.rb
実績を見てしまうとネタバレになるのですが、それぞれが全く異なった方法で実装されているので、これだけで例としては十分でしょう。このファイルの前半の方は、実績プラグイン自信の実装です。このプラグイン、mikutterプラグインとしても結構興味深いのですが、それについては別の機会に触れたいと思います。
ヒントのタイミング
最後に、一応、実績のヒント(hint)がユーザに提示される条件を説明しておきます。毎回mikutterが起動される度に、
- 未達成で
- hidden が偽か未指定
の実績のうち、ランダムに一つを選出します。その実績に上記条件に当てはまる前提実績があれば、再帰的にそれを辿って、最終的に一つだけ実績を選んでそのhintの値を表示します。
前提とされている数が多い実績のほうが、表示される可能性が高くなりますね。前提実績が解除の邪魔をしているような実績のヒントは表示されません。
また、ユーザには、mikutterを再起動する以外に新しいヒントを得る方法がありません。Twitterクライアントの使い方なんて一気に勉強するものではありません。ゆっくり覚えたらいいし、もっと言えばTwitterなんてしてないでとっととレポートを書くべきです。mikutterのせいで単位を落としたって、私にはふぁぼることしかできません。
まとめ
使えそうで使えない、楽しそうで案外どうでもいい、実績機能について紹介しました。かなり変な機能なので、構想はかなり前からあったにも関わらず、0.2.1では導入を見送っていました。DRを言いたかっただけです。