どうも、はにぃでぇす。
たまにツイッターのアカウント消したくなるのですが、ツイ廃やってます。
たまたま目に入ったこのツイート。
— Lost (@lost_faultinya) April 19, 2018
彼は必要もなく話を盛る性格ではない、ということを十分に私は理解しているのでこれに興味を持ちました。
直ちにツイートに提示されているリンクを開くことにしました。
Introduction
Flowyとは
複数の待機が必要なフェイズによって構成される一連の処理(フロー)を簡潔に記述するためのフレームワークです。
Generatorを使ったコルーチンによって実現しています。
また、Flowyはリアクティブプログラミングの実現を可能としますが、それ自体を実現しようとするものではありません。
あくまで待機を可能にするだけです。
(https://github.com/NewDelion/Flowy/wiki)
非同期ライクなルックスのコーディングっぽいですが、実際には非同期とは言い切れないようです。
簡潔にPocketMine-MPのコードがかけそうなところに魅力を感じました。
Practice
プラグインのsrcフォルダ直下にFlowyのファイル群の入った、Flowyフォルダを用意してください。
一番下の方に書いてある実装例のプラグインが参考になると思います。
<?php
namespace FlowExample;
use function Flowy\delay;
use Flowy\Flowy;
use function Flowy\listen;
use pocketmine\event\player\PlayerMoveEvent;//使うイベントを記載するように。
use pocketmine\event\player\PlayerInteractEvent;
class FlowExample extends Flowy{//extendsで各種関数を取り入れます。
//+------------------------------------------------------------------+
//|起動時の読み込み。 |
//+------------------------------------------------------------------+
function onEnable(){
$this->start($this->test());//test関数を1度だけ呼び出します。
$this->start($this->test2());//test2関数を1度だけ呼び出します。
$this->start($this->test3());//test3関数を1度だけ呼び出します。
}
//+------------------------------------------------------------------+
//|動くと、moving と言われる機能 |
//+------------------------------------------------------------------+
function test(){
while(true){//永久にループを抜けることはありません。
/** @var PlayerMoveEvent $event */
$event = yield listen(PlayerMoveEvent::class); //イベントを待機させる
$player = $event->getPlayer();
$player->sendMessage("moving".time());
}
}
//+------------------------------------------------------------------+
//|石ブロックを触ると、interactedと言われる。(1度だけ) |
//+------------------------------------------------------------------+
function test2(){
/** @var PlayerInteractEvent $event */
$event = yield listen(PlayerInteractEvent::class)//イベントを待機させる
->filter(
/**Interactイベントが起きて なおかつ この関数がtrueを返すことを条件と設定します。
条件が満たされれば、”実行部分”の実行に移ります。そうでなければ、イベントが起こるのを待ち続けます。 **/
function ($ev) {
/** @var PlayerInteractEvent $ev */
return
$ev->getBlock()->getId() == 1;//stone
});
//実行部分
$event->getPlayer()->sendMessage("interacted".time());
//一度上のメッセージ送信が終われば、このtest2のイベント待機のための関数は終了される、二度目以降の石をタップする行為を検出することはありません。
}
//+------------------------------------------------------------------+
//|草ブロックを触ると、3秒を数えてunixtimeを言われる。(何回でも) |
//+------------------------------------------------------------------+
function test3(){
/** @var PlayerInteractEvent $event */
$event = yield listen(PlayerInteractEvent::class)
->filter(
function ($ev) {
/** @var PlayerInteractEvent $ev */
return
$ev->getBlock()->getId() == 2;//grass
});
$event->getPlayer()->sendMessage("please wait".time());
yield delay(20*3); //遅延を作ってみます。 20tick = 1秒 を3倍しています。
$event->getPlayer()->sendMessage("after 3 second...".time());
$this->start($this->test3());//test3関数を1度だけ呼び出します。自身をループして呼び出すことになるので、test1のようにwhileで挟んだような振る舞いをします
}
}
ざっと説明に入ります。おおむねコメントで設位はしていますが、、、。
これでFlowyの関数を開始させます。メインスレッドが固まることはありません。
$this->start($this->test());
function test(){
を見てもらうとわかるのですが、
whileで挟んでないと1度しかイベントを検出させることができません。
ちなみにここにおいて、whileをさせていてもメインスレッドはやはり固まりません。
また関数内での一時停止は、
yield delay(20*秒);
を用います。
あとはコメントを読めばわかると思います。
Conclusion
Flowyを使えば、従来のイベント発生時に呼ばれる関数内での処理という形ではなく、単一の関数内で手続き型を用いて記述できることがわかるでしょう。現時点で私はこれの使い道を知りませんが、なんかできそうな気はします。もっとも私はプラグイン開発をしません、資料作りがしたかっただけです。
このページを資料としてFlowyを使ってくれる人がいたら、うれしく思います。
*私はそこまでPocketMineプラグインに詳しくないので、記載に誤った箇所があれば、”コメントで”指摘してくれるといいと思います。
プラグイン実装を見つけたので、のせとく。https://github.com/OtorisanVardo/ButtonCall