[PMMP]パーミッションを使う

※この記事では執筆時点で安定バージョンのPocketMine-MP API4.0.0に準拠しています。

# パーミッションとは
権限です(そりゃそうだ)、コマンドの実行権限を制御するのに使われることが一番多いと思います。
でも、どうやって使えばいいのか、なんで使ったほうがいいのか分からない人もいるかもしれません。
使ってみるとそこまで難しくはないので、是非使ってみてください。お願いします。使ってください.......

# パーミッションを使う理由
- OPであるかどうかに依存しない
  - プレイヤーごとにパーミッションを与えるか制御することができる(e.g. VIPユーザー(OPではない)もOP専用コマンドを使用できるようにする)
- コマンドリスト(helpなど)にパーミッションが無くて使えないコマンドを表示させない
- `Permissible->hasPermission(DefaultPermissions::ROOT_OPERATOR)`とか訳分からん長い謎の定型文を書かなくていい！！

# 使い方

## パーミッションを登録する
パーミッションは、許可する物事ごとに作成します。
パーミッションを複数の許可で共有してはいけません。(`myplugin.op`や`myplugin.everyone`などを作ってそのパーミッションを共用するなど)

- パーミッション名
  - 一般的には`.`区切りのアルファベットを使用します。他プラグインとの競合を防ぐために、[接頭辞としてプラグイン名を追加すると良い](https://qiita.com/PJZ9n/items/1ca6423da373b2f24bc9#%E3%83%91%E3%83%BC%E3%83%9F%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3%E5%90%8D)です。(e.g. `myplugin.command.hoge`, `myplugin.land_protection.bypass`)
- 説明
  - このパーミッションによって何が許可されるのかの説明です。プラグインの開発方針によって、英語でも日本語でも良いです。(e.g. `/hoge コマンドの使用を許可します`, `土地保護をバイパスすることを許可します`)
- デフォルト値
  - このパーミッションはデフォルトで誰に許可されるか。以下の表のどれかを設定します。沢山あって難しそうに見えますが、実際に使うのは`op`, `notop`, `true`, `false`だけです。

| デフォルト値 | 許可対象 |
| --- | --- |
| op | OP |
| isop | OP |
| operator | OP |
| isoperator | OP |
| admin | OP |
| isadmin | OP |
| !op | OP以外 |
| notop | OP以外 |
| !operator | OP以外 |
| notoperator | OP以外 |
| !admin | OP以外 |
| notadmin | OP以外 |
| true | 全員 |
| false | 誰にも許可しない |

※`false`は、コンソールのみに許可として使用されることも多いです。(コンソールはパーミッションの許可に左右されないため)

これは、コードで確認することもできます:
https://github.com/pmmp/PocketMine-MP/blob/4.0.0/src/permission/PermissionParser.php#L37-L54

plugin.ymlで以下のように設定することで、パーミッションを登録できます。複数設定することができます。

```yaml:plugin.yml
permissions:
  パーミッション名1:
    description: 説明1
    default: デフォルト値1
  パーミッション名2:
    description: 説明2
    default: デフォルト値2
```

## パーミッションをコマンドで使用する

### plugin.ymlでコマンドを追加した場合
上級者でない場合この方法でコマンドを登録するのが安全です。(パーミッションに設定ミス(誤字など)があったらエラーで止まってくれる)

```yaml:plugin.yml
commands:
  permission: パーミッション名
```
※`description`や`usage`などを設定しても良いですがここでは省略しています。

よくある間違いで、ここの`permission`に`op`とか`true`とか指定してしまうことがありますが、それだと動作しないので注意！

メインクラスの`onCommand`メソッドの中ではパーミッションの条件分岐など、なにもしなくてOK！
`Permissible->hasPermission(DefaultPermissions::ROOT_OPERATOR)`などの条件分岐があったら上手く動作しないので削除しておきましょう。
それで動いているか不安な場合は、実際に動作確認してみると良いです。

### コマンドをCommandMapで登録している場合
コンストラクタ(`__construct`)などに`$this->setPermission("パーミッション名");`を追加してパーミッションを設定します。

実装によっては`$command->setPermission("パーミッション名");`となることもあるかもしれません。(要はコマンドのオブジェクトに対してsetPermission()を呼び出せば良い)

このとき、パーミッション名は`;`区切りで複数指定することができます。(e.g. `myplugin.command.hoge;myplugin.foo.bar`)複数指定した場合、そのうちのどれか1つでもパーミッションを持っていたらパーミッションを持っている判定になります。(自分は使ったことないけど...)

さらにコマンドの実行時に自分でメソッドを呼び出してパーミッションの確認をする必要があります。
ただし、以下の場合はすでにされているので不要です。

- そのコマンドのクラスが`PluginCommand`を継承していて、`CommandExecutor`(つまり`onCommand`のこと)を使用している場合
- [Commando](https://github.com/CortexPE/Commando/tree/6b3b6e15fdbd3cdef44b52cbd56023b76dddac60)ライブラリを使用している場合(執筆時点)
- それ以外のライブラリやクラスなどを使用している場合で、実際にコマンドを処理するメソッドより上で`testPermission`メソッドが呼ばれているか、パーミッションがチェックされている場合(多分それをしている人は初心者ではないと思うのでわかると思いますが...)

#### 上記に当てはまらない場合

次のような条件分岐を配置してください。
このコードは[早期リターン](https://www.google.com/search?q=%E6%97%A9%E6%9C%9F%E3%83%AA%E3%82%BF%E3%83%BC%E3%83%B3)を使用していますが、普通のifでも良いし、好きな方法で大丈夫です。(`testPermission`メソッドで実行者がコマンドを実行するパーミッションを持っているかどうかがboolで返ってきます)
パーミッションを持っていない場合は自動で[パーミッションが不足している旨のメッセージが送信される](https://github.com/pmmp/PocketMine-MP/blob/4.0.0/src/command/Command.php#L119-L123)ので、メッセージを別途送信する必要はありません。

```php
public function execute(CommandSender $sender, string $commandLabel, array $args)
{
    if (!$this->testPermission($sender)) {
        return;
    }
    //処理
}
```

※[Command->testPermissionSilent()](https://github.com/pmmp/PocketMine-MP/blob/4.0.0/src/command/Command.php#L128-L141)や、[Command->setPermissionMessage()](https://github.com/pmmp/PocketMine-MP/blob/4.0.0/src/command/Command.php#L225-L227)などを使って動作をカスタマイズすることができますが、ここでは紹介しません。詳しくはコードを参照してください。

## パーミッションをコマンド以外で使用する

任意の場所で`Permissible->hasPermission()`を呼び出すことで、`Permissible`(プレイヤーなど)がパーミッションを持っているかを確認することができます。

具体的な例

```php
public function onProtectedAreaBreak(BlockBreakEvent $event): void
{
    $player = $event->getPlayer();
    if (!$player->hasPermission("myplugin.land_protection.bypass")) {
        //保護をバイパスできるパーミッションを持っていない場合はキャンセルする
        $event->cancel();
    }
}
```

## Permissibleにパーミッションを付与する
`Permissible->addAttachment()`を呼び出すことで`Permissible`(プレイヤーなど)にパーミッションを付与することができます。

例

```php
assert(!$player->hasPermission(DefaultPermissions::ROOT_OPERATOR));
//プレイヤーがVIPだったら
if ($player->hasVip()) {
    //gamemodeコマンドの使用を許可する
    $player->addAttachment($plugin, "pocketmine.command.gamemode", true);
}
```

逆に、パーミッションを剝奪することもできます。

例

```php
//プレイヤーがやばい人だったら
if ($player->isSpammer()) {
    //meコマンドの使用を拒否する
    $player->addAttachment($plugin, "pocketmine.command.me", false);
}
```

※PMMP標準のパーミッションを使う場合は[DefaultPermissionNames](https://github.com/pmmp/PocketMine-MP/blob/4.0.0/src/permission/DefaultPermissionNames.php)の定数を使用したほうが良いです。分かりやすくするために文字列を直接指定しています。

# さいごに
この記事をお読み頂きありがとうございます。参考になりましたら是非LGTMをお願いします。
また問題点などありましたらコメントや編集リクエストなどお気軽に送信してください。よろしくお願いします。
ありがとうございました。