schedulerを使いこなす  [PocketMine-MP]

# はじめに
この記事では、MCBE用サーバーソフトウェアであるPocketMine-MP利用者に向けて書いています。
他のコンテンツでも用いる名称を使用しますがその点ご理解ください。

また、この記事は初心者、或いは作成に慣れてきた中級者に向けたものです。
　
# scheduler(スケジューラ)について
PMMPが実装している、遅延、非同期処理などを可能にする機能です。
プラグインでは 遅延(リピート)処理をする際は **Task**を継承したクラスを作成し、
TaskSchedulerから呼び出します。

AsyncTaskは最近(?)変わって AsyncPoolから``submitTask()``関数で実行できます。

※昔実装されていたCallbackTaskは非推奨なので触れません。
ちなみにsteadfast2はまだあるみたいです。
　
# よくある遅延処理

適当な利用例で よくある使い方を見てみましょう。

例えば、プレイヤーがチャットを送った***2秒後***に
**``OK!``**と送る機能を作ってみます。

細かく言うと例外処理が必要になりますが、
例を複雑化したくないので割愛します。

```php:sample.php
class Sample extends PluginBase implements Listener {
    function onChat(PlayerChatEvent $event){
        $player = $event->getPlayer();
        $this->getScheduler()->scheduleDelayTask(new MessageTask($player), 20 * 2);
    }
}

class MessageTask extends Task {
    public function __construct(Player $player){
        $this->player = $player;
    }
    public function onRun(int $tick){
        $this->player->sendMessage("OK!");
    }
}
```

こんな感じが多いのではないでしょうか。
　

ただ、こういった単純なものならば
**無名クラス**を用いてこのように書くケースもあります。

```php:sample.php
class Sample extends PluginBase implements Listener {
    function onChat(PlayerChatEvent $event){
        $player = $event->getPlayer();
        $this->getScheduler()->scheduleDelayTask(
            new class($player) extends Task{
                public function __construct(Player $player){
                    $this->player = $player;
                }
                public function onRun(int $tick): void{
                    $this->player->sendMessage("OK!");
                }
        }, 20 * 2);
    }
}
```

※$playerの部分 パーサーが赤線引いてますがちゃんと動きます。

PMMPプラグイン作成のみを手掛けている方の中に
この構文が見慣れない方がいるかもしれませんが、なんとなく意味は分かると思います。
よって割愛。

新しいクラスも定義しなくてよく、ややネストが深くなりますが
簡易的に書けますね。
　

これをさらに簡易的に書くには、**ClosureTask**を使うと便利でしょう。
なにそれ？と思われた方もいると思います。
あとで説明します。
　
# 非同期処理
ゲームにラグを生じさせたくないとき等に使用します。

外部との通信を行ったり、大きなデータを扱ったり
I/O処理だったり... パフォーマンスを考えるならかなり使いどころがあると思います。

使い方の説明...をしようと思いましたが~~面倒ですし~~、既に記事を見つけたのに
あらためて書くのも気が滅入るので こちらの記事を参考にしてください。

> PocketMine-MPでAsyncTaskを使ってみる
> @famima65536
>https://qiita.com/famima65536/items/7ffd26266d7205298b7f

丸投げもアレなので
私が書いたプラグインの一部で使用したものを貼っておきます。

https://github.com/MyDeacy/MoneyLevel/blob/master/src/mydeacy/moneylevel/tasks/RankingTask.php

　
さて、主な使い方が分かったところで 色々なタスクについて触れます。
　
# 色々なタスク
## ClosureTask
これは、引数に**クロージャ(無名関数)**を渡します。
onRun()関数で実行される処理を引数として書くことができます。

例を書いてみます。
挙動は、**よくある遅延処理** で用いた例と同一とします。

```php:ClosureTaskSample
$this->getScheduler()->scheduleDelayedTask(new ClosureTask(
    function (int $currentTick) use ($player): void {
        $player->sendMessage("OK!");
    }
), 20 * 2);
```

すっきり書くことができました。

## BulkCurlTask
その名の通り、Curl処理を行うためのものです。

このクラスは**AsyncTask**を継承しており、非同期処理用です。

使い方は、AsyncTaskと同じように BulkCurlTaskを**継承**したクラスを用意します。

ここで違うのは、コンストラクタで配列を渡すと、
onRun()メソッド内で Internet::SimpleCurl()関数を使い、
結果をsetResult()してくれます。

渡された結果は、getResult()関数で取得できます。

配列内に必要な情報はソースコードを参考にしてください。
https://github.com/pmmp/PocketMine-MP/blob/master/src/pocketmine/scheduler/BulkCurlTask.php

また、AsyncTaskを継承しているため、実行は
``AsyncPool->submitTask()``で行います。
　
## FileWriteTask
その名の通り、ファイルに書き込みを行うためのタスクです。

こちらもAsyncTaskを継承しており、非同期用です。

コンストラクタに パス、内容を入れることでonRun()時に
指定のファイルへ書き込みを行ってくれます。

書き込みのみの処理ならば無名クラスでスッキリ書けますね。
　
## GarbageCollectionTask
GC(メモリのお掃除)を行います。引数などは不要です。

定期実行なんてことしてもよさそうです。
　
##その他
紹介してないのも少しあります。

https://github.com/pmmp/PocketMine-MP/tree/master/src/pocketmine/scheduler

　
#おわりに
スケジューラの機能は結構使うと思うので
是非効率的に書いてください