1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

pmmpの開発環境を無課金で整えて、簡単なプラグインを作ろう!(vscode編)

Last updated at Posted at 2025-06-23

イントロ

この記事はMinecraftサーバ開発・運営 Advent Calendar 2021 16日目です。
1285日の遅刻ですよろしくお願いします

pmmp界隈の皆さんお元気にされていますか?私は2025年になっても未だpmmpと戯れている囚人です。
この記事では、課金エディタ(1年間の使用権利 約1万4000円)であるphpstromになるべく近い環境をvscodeで整えるまでの記事です。

まずはこの記事で、ダウンロードフォルダにpmmpをの実行展開、devtool.pharがプラグインフォルダにある状況が手元にあることを前提として解説します。

vscodの設定内容の指示ミスという致命的なミスが見つかっています。申し訳ございません。
パソコンが修理され次第、修正します。

お断り

お断りしますが、課金してphpstrom(1.4万)で開発するほうが構築の面でも、プログラミング上のQOLの面でも、開発ガチるなら圧倒的に楽です。
phpstromには、フォールバックライセンス制度があり、1度でも年間ライセンスを購入すれば特定の過去のバージョンが使い放題になります。なお、ライセンスが有効の間は最新バージョンを使用することができます。
また、学生で、学生の証明(GitHub Education)ができれば、phpstromなどを無料で使用することができ、卒業時には40% offでフォールバックライセンス付きの購入することができます。
phpstromでの開発編は気が向いたら書きます。

vscodeでのセットアップは非常に複雑で、非常に厳しい道のりになります。覚悟の上で進んでください。

キーボードショートカット、ctrl+c(コピー)とctrl+v(貼り付け)、ctrl+a(全選択)はすでに習得済みという前提を元に解説します。

必要なもの

Windows 10 or Windows 11のパソコン
無制限のインターネット回線
ちゃんとループバックしてくれるルーター(ソフトバンクAIRなどはだめ)

vscodeを入手する

下記からvsocdeをインストールしましょう。
https://code.visualstudio.com/

インストーラーを起動し、ライセンス条約に同意してください。

契約という物騒な言葉がかかれていますが、ソフトウェアを使ったり、配布したり、引用したりする際のしていいこと、したらだめなことなどが書かれた文章に同意するだけなので、実際に契約が発生するわけはありません。

image.png

お好みに応じて編集します。

  • エクスプローラーのファイルコンテキスト...: ファイルを右クリックした右クリックメニュー(win11の場合詳細表示)に [codeで開く]を追加します。
    • あると非常に便利です。
  • エクスプローラーのディレクトリコンテキスト...: ディレクトリを右クリックした右クリックメニュー(win11の場合詳細表示)に [codeで開く]を追加 します。
    • あると非常に便利です。
    • ないと後々困ります。
  • サポートされてえいるファイルの種類のエディタ...: phpファイルなどのプログラム関連付けを勝手にvscodeに変更します。
  • pathへの追加: git cliなどを使うときに便利です。

image.png

インストールをクリックします。
image.png

インストール完了したら、初回起動のためにウィザードを閉じます。
するとこのような画面がでてきますが、いったん閉じましょう。

image.png

composerをダウンロードする

composerとは、phpのパッケージマネージャであり、1つのコマンドでpmmpの依存関係をすべて取得できる優れものです。
下記にpmmpがあることを確認してください。ない場合は下記の記事に従ってインストールをしてください

C:\Users\<ユーザー名>\Downloads\PocketMine-MP

composerフォルダを作成してください。

C:\Users\<ユーザー名>\Downloads\PocketMine-MP\composer

PocketMine-MPフォルダにbinフォルダがあることを確認してください。ない場合はpmmpをダウンロードフォルダにインストールしてください

次にここからcomposer.pharをダウンロードします。

その後、composerフォルダにコピペしてください

C:\Users\<ユーザー名>\Downloads\PocketMine-MP\composer\composer.phar

次に、コマンドプロントを開きます。
composerフォルダに移動し、アドレス欄にcmdと入力します。

image.png

黒い画面が出ましたか?出たのであれば続行してください

image.png

次に、次のコマンドを実行します

..\bin\php\php.exe .\composer.phar req pocketmine/pocketmine-mp *

こんな感じのメッセージが出れば成功です!

C:\Users\ESv87g9gvea4\Downloads\PocketMine-MP\composer>..\bin\php\php.exe .\composer.phar req pocketmine/pocketmine-mp *
./composer.json has been created
Running composer update pocketmine/pocketmine-mp
Loading composer repositories with package information
Updating dependencies
Lock file operations: 22 installs, 0 updates, 0 removals
  - Locking adhocore/json-comment (1.2.1)
  - Locking brick/math (0.13.1)
  - Locking netresearch/jsonmapper (v5.0.0)
  - Locking pocketmine/bedrock-block-upgrade-schema (5.1.0)
  - Locking pocketmine/bedrock-data (5.1.0+bedrock-1.21.90)
  - Locking pocketmine/bedrock-item-upgrade-schema (1.14.0)
  - Locking pocketmine/bedrock-protocol (39.0.0+bedrock-1.21.90)
  - Locking pocketmine/binaryutils (0.2.6)
  - Locking pocketmine/callback-validator (1.0.3)
  - Locking pocketmine/color (0.3.1)
  - Locking pocketmine/errorhandler (0.7.0)
  - Locking pocketmine/locale-data (2.25.1)
  - Locking pocketmine/log (0.4.0)
  - Locking pocketmine/math (1.0.0)
  - Locking pocketmine/nbt (1.1.1)
  - Locking pocketmine/pocketmine-mp (5.30.0)
  - Locking pocketmine/raklib (1.2.0)
  - Locking pocketmine/raklib-ipc (1.0.1)
  - Locking pocketmine/snooze (0.5.0)
  - Locking ramsey/collection (2.1.1)
  - Locking ramsey/uuid (4.8.1)
  - Locking symfony/filesystem (v6.4.13)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 22 installs, 0 updates, 0 removals
  - Installing adhocore/json-comment (1.2.1): Extracting archive
  - Installing netresearch/jsonmapper (v5.0.0): Extracting archive
  - Installing pocketmine/bedrock-block-upgrade-schema (5.1.0): Extracting archive
  - Installing pocketmine/bedrock-data (5.1.0+bedrock-1.21.90): Extracting archive
  - Installing pocketmine/bedrock-item-upgrade-schema (1.14.0): Extracting archive
  - Installing ramsey/collection (2.1.1): Extracting archive
  - Installing brick/math (0.13.1): Extracting archive
  - Installing ramsey/uuid (4.8.1): Extracting archive
  - Installing pocketmine/binaryutils (0.2.6): Extracting archive
  - Installing pocketmine/nbt (1.1.1): Extracting archive
  - Installing pocketmine/math (1.0.0): Extracting archive
  - Installing pocketmine/color (0.3.1): Extracting archive
  - Installing pocketmine/bedrock-protocol (39.0.0+bedrock-1.21.90): Extracting archive
  - Installing pocketmine/callback-validator (1.0.3): Extracting archive
  - Installing pocketmine/errorhandler (0.7.0): Extracting archive
  - Installing pocketmine/locale-data (2.25.1): Extracting archive
  - Installing pocketmine/log (0.4.0): Extracting archive
  - Installing pocketmine/raklib (1.2.0): Extracting archive
  - Installing pocketmine/raklib-ipc (1.0.1): Extracting archive
  - Installing pocketmine/snooze (0.5.0): Extracting archive
  - Installing symfony/filesystem (v6.4.13): Extracting archive
  - Installing pocketmine/pocketmine-mp (5.30.0): Extracting archive
3 package suggestions were added by new dependencies, use `composer suggest` to see details.
Generating autoload files
4 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
No security vulnerability advisories found.

C:\Users\ESv87g9gvea4\Downloads\PocketMine-MP\composer>

vscodeをカスタマイズする。

プラグインをインストールする

windowsの検索バー等に「code」と入れ、vscodeを起動します。

こんな感じの画面が出ます。
image.png

次にここをクリックしてください。
image.png

こんな感じの画面になると思います。
image.png

ここに下記の文字を入力します。

PHP Intelephense

これはメインのランゲージ(補完)サーバーです。

image.png

ここをクリックします。
image.png

表示されたウインドウ内で、「インストール」をクリックします。
image.png

次に入力された文字を削除し、

PHP DocBlocker

を入力します。

これはphpdocを書くための補助ツールです。

image.png

次に入力された文字を削除し、

PHP import checker

を入力します。
これは未使用のuse文などをハイライトしてくれる機能です。

image.png

組み込みの補完機能を無効化する

画像では無効化してますが、誤りであるため、
PHP Language Basicsは無効化しないでください

vscodeに組み込まれた必要最低限のphp補完機能を無効します。無効化しないと悲しいことが起きるのでスキップしないでください。

次に入力された文字を削除し、次の文字を入力します。

@builtin php

PHP Language Featuesをクリックします。

Disableをクリックします。
image.png

日本語化する

入力された文字を削除し、

日本語

と入力します。

image.png

告知ポップアップから、change language and restartを選択します。
image.png

設定を編集する

このままではオートセーブなどが無効なので有効にします。

歯車マーク、settingから設定を有効化します。

image.png

開いたら、このボタンを正確にクリックします

image.png

こんな感じの画面になったら成功です。
image.png

内容物をすべて削除し、次のようにします。

ユーザー名はパソコンのユーザー名に置換してください
日本語ユーザー名の場合対応していない可能性があります。

by https://github.com/NeiroNetwork/IDE_Configs/blob/main/.vscode/settings.json

{
    "files.autoSave": "afterDelay",
    "php.validate.executablePath": "C:\\Users\\ユーザー名\\Downloads\\PocketMine-MP\\bin\\php\\php.exe",
    "files.associations": {
        "*.module": "php"
    },
    "php.validate.run": "onType",
    "intelephense.environment.includePaths": [
        "C:\\Users\\ユーザー名\\Downloads\\PocketMine-MP\\composer\\vendor"
    ],
    "php.suggest.basic": false,
    "editor.insertSpaces": false,
    "[yaml]": {
		"editor.insertSpaces": true,
		"editor.tabSize": 2
	},
    "[json]": {
		"editor.insertSpaces": true,
		"editor.tabSize": 4
	},
	"[php]": {
		"editor.tabSize": 4
	}
}

オプションの設定

日本語などを絶対黄色くしない設定(非推奨)
}の前に追加します。

    "editor.unicodeHighlight.ambiguousCharacters": false,
    "editor.unicodeHighlight.invisibleCharacters": false,
    "editor.unicodeHighlight.includeComments": false,
    "editor.unicodeHighlight.includeStrings": false,
    "editor.unicodeHighlight.nonBasicASCII": false,

こんな感じになれば成功です。

ユーザー名は編集しましたか?

image.png

そしたらctrl+sを1回押して、次の作業をします。

コードスニペットを編集する

phpstromに近づけるために、vscodeにphpのコードスニペットを追加します。

歯車アイコン→スニペットを選択します

image.png

表示された入力欄にphp、[エンター]と入力します。

image.png

こうなれば成功です。

image.png

下記のコードスニペットをすべてコピーし、上書き貼り付けしてください

{
	// Place your snippets for php here. Each snippet is defined under a snippet name and has a prefix, body and 
	// description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
	// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. Placeholders with the 
	// same ids are connected.
	// Example:
	// "Print to console": {
	// 	"prefix": "log",
	// 	"body": [
	// 		"console.log('$1');",
	// 		"$2"
	// 	],
	// 	"description": "Log output to console"
	// }
	"if": {
		"prefix": "if_tab",
		"body": [
			"if($1){",
			"\t",
			"}",
		],
	},
	"foreach": {
		"prefix": "foreach",
		"body": [
			"foreach($1 as \\$key => \\$value){",
			"\t$2",
			"}",
		],
	},
	"<?php": {
		"prefix": "<?php",
		"body": [
			"<?php",
		],
	},
	"<?php class": {
		"prefix": "<?php",
		"body": [
			"<?php",
			"",
			"declare(strict_types=1);",
			"",
			"namespace $1;",
			"",
			"class $2{",
			"\t$3",
			"}",
		],
	},
	"break;": {
		"prefix": "break;",
		"body": [
			"break;",
		]
	},
	"__construct": {
		"prefix": "__construct",
		"body": [
			"__construct",
		]
	},
	"__construct fun": {
		"prefix": "__construct",
		"body": [
			"public function __construct($2){",
			"\t$3",
			"}",
		]
	},
	"fun": {
		"prefix": "fun",
		"body": [
			"public function $1($2){",
			"\t$3",
			"}",
		]
	},
	"var_dump();": {
		"prefix": "var_dump",
		"body": [
			"var_dump($1);",
		]
	},
	"info": {
		"prefix": "info",
		"body": [
			"\\$this->getLogger()->info($1);",
		]
	},
	"static": {
		"prefix": "static",
		"body": [
			"static",
		]
	},
	"extends": {
		"prefix": "ex",
		"body": [
			"extends ",
		]
	},
	"extends1": {
		"prefix": "extends",
		"body": [
			"extends ",
		]
	},
	"instanceof": {
		"prefix": "instanceof",
		"body": [
			"instanceof",
		]
	},
	"instanceof1": {
		"prefix": "ins",
		"body": [
			"instanceof",
		]
	},
	"public": {
		"prefix": "public",
		"body": [
			"public ",
		]
	},
	"return": {
		"prefix": "return",
		"body": [
			"return ",
		]
	},
	"true": {
		"prefix": "true",
		"body": [
			"true",
		]
	},
	"false": {
		"prefix": "false",
		"body": [
			"false",
		]
	},
	"private": {
		"prefix": "private",
		"body": [
			"private",
		]
	},
	"protected": {
		"prefix": "protected",
		"body": [
			"protected",
		]
	},
	"pubf": {
		"prefix": "pubf",
		"body": [
			"public function $1($2): ${3|void,int,string,array,bool,mixed|}{",
			"\t$4",
			"}",
		]
	},
	"pubsf": {
		"prefix": "pubsf",
		"body": [
			"public static function $1($2): ${3|void,int,string,array,bool,mixed|}{",
			"\t$4",
			"}",
		]
	},
    "prof": {
		"prefix": "prof",
		"body": [
			"protected function $1($2): ${3|void,int,string,array,bool,mixed|}{",
			"\t$4",
			"}",
		]
	},
	"prosf": {
		"prefix": "prosf",
		"body": [
			"protected static function $1($2): ${3|void,int,string,array,bool,mixed|}{",
			"\t$4",
			"}",
		]
	},
	"prif": {
		"prefix": "prif",
		"body": [
			"private function $1($2): ${3|void,int,string,array,bool,mixed|}{",
			"\t$4",
			"}",
		]
	},
	"prisf": {
		"prefix": "prisf",
		"body": [
			"private static function $1($2): ${3|void,int,string,array,bool,mixed|}{",
			"\t$4",
			"}",
		]
	},
	"thr": {
		"prefix": "thr",
		"body": [
			"throw new $1"
		]
	},
	"thrRuntimeException": {
		"prefix": "RuntimeException",
		"body": [
			"throw new \\RuntimeException(\"\");"
		]
	},
	"continue": {
		"prefix": "continue",
		"body": [
			"continue;",
		]
	},
	"@phpstan-var": {
		"prefix": "@phpstan-var",
		"body": [
			"@phpstan-var $1",
		]
	},
	"@phpstan-return": {
		"prefix": "@phpstan-return",
		"body": [
			"@phpstan-return $1",
		]
	},
	"@phpstan-param": {
		"prefix": "@phpstan-param",
		"body": [
			"@phpstan-param $1",
		]
	},
	"@phpstan-var array<>": {
		"prefix": "@phpstan-var array<>",
		"body": [
			"@phpstan-var array<$1, $2>",
		]
	},
	"@phpstan-return array<>": {
		"prefix": "@phpstan-return array<>",
		"body": [
			"@phpstan-return array<$1, $2>",
		]
	},
	"@phpstan-param array<>": {
		"prefix": "@phpstan-param array<>",
		"body": [
			"@phpstan-param array<$1, $2>",
		]
	},
	"@phpstan-var list<>": {
		"prefix": "@phpstan-var list<>",
		"body": [
			"@phpstan-var list<$1>",
		]
	},
	"@phpstan-return list<>": {
		"prefix": "@phpstan-return list<>",
		"body": [
			"@phpstan-return list<$1>",
		]
	},
	"@phpstan-param list<>": {
		"prefix": "@phpstan-param list<>",
		"body": [
			"@phpstan-param list<$1>",
		]
	},
	"declare(strict_types=1); 2":{
		"prefix": "declare",
		"body": [
			"declare(strict_types=1);"
		]
	},
	"declare(strict_types=1);":{
		"prefix": "decl",
		"body": [
			"declare(strict_types=1);"
		]
	},
	"onCommand": {
		"prefix": "onCommand",
		"body": [
			"public function onCommand(CommandSender $$sender, Command $$command, string $$label, array $$args) : bool{",
			"\tswitch($$label){",
			"\t\tcase '$1':",
			"\t\t\t$2",
			"\t\t\tbreak;",		
			"\t}",
			"}",
		]
	},
	"re": {
		"prefix": "re",
		"body": [
			"return $1;",
		]
	},
	"private ": {
		"prefix": "pr",
		"body": [
			"private $1",
		]
	},
  "foreach ($array as $value)": {
    "prefix": "fore",
    "body": [
      "foreach (${1:\\$array} as ${2:\\$value}) {",
      "\t$0",
      "}"
    ],
    "description": "PHP foreach over values"
  },
  "foreach ($array as $key => $value)": {
    "prefix": "forek",
    "body": [
      "foreach (${1:\\$array} as ${2:\\$key} => ${3:\\$value}) {",
      "\t$0",
      "}"
    ],
    "description": "PHP foreach over keys and values"
  },
	"for ($i = 0; $i < count($array); $i++)": {
	"prefix": "fori",
	"body": [
		"for (\\$${1:i} = ${2:0}; \\$${1} < ${3:count(\\$array)}; \\$${1}++) {",
		"\t$0",
		"}"
	],
	"description": "PHP for loop with editable start index"
	}
}

こうなれば成功です。
image.png

そしたらctrl+sを1回押してから閉じます。これで、プラグイン制作環境のほぼ90%が完了しました。
お疲れ様でした。
いったんvsocdeは閉じてokです。

プラグインテンプレートの生成

1記事目の方法で、start.cmdを起動し、サーバーを待機状態にします。
次に、コンソールに次のコマンドを入力します。
これはDevToolsプラグインによる機能です。

自分の名前等に編集してください

genplugin プラグインの名前 プラグインの製作者

次のようになれば成功です!

genplugin MyFirstPlugin DaisukeDaisuke
Command output | Created skeleton plugin MyFirstPlugin in C:\Users\ESv87g9gvea4\Downloads\PocketMine-MP\plugins\MyFirstPlugin\

サーバーをctrl+cまたはstopコマンドで終了してください。

次のようになった場合は、DevTools.pharを導入する必要があります

genplugin MyFirstPlugin DaisukeDaisuke
Command output | Unknown command: genplugin. Use /help for a list of available commands.

エラー時の対処法

  1. サーバーを停止します
  2. ここからDevTools.pharをダウンロードします。
  3. ダウンロードフォルダからC:\Users\ユーザー名\Downloads\PocketMine-MP\plugins\DevTools.pharになるようにコピーします。
  4. サーバーを起動します。
  5. 再度コマンドを試します。

PocketMine-MP\plugins\MyFirstPlugin\にプラグインのスケルトンが生成されているので、右クリックメニューからcodeで開くを選択します。

image.png

image.png

次のような画面になれば成功です!

「はい、作成者を信頼します」をクリックします。

image.png

ファイルブラウザを開き、src→main.phpをクリックして、プラグインのメインクラスファイルを開きます。

image.png

image.png

次の画面になれば正常にエディタを開けています!
image.png

Q: エディタで文字に色がつかないんだけど

image.png

A:
PHP Language Basicsを間違えて無効化しちゃってます。
拡張機能の検索欄に@builtin phpと入力して必ず無効(有効の状態)になってるか確認してください

image.png

簡単なプラグインを作る

起動時にメッセージをコンソールに送るプラグイン

今はこのようになっていると思います。

<?php

declare(strict_types=1);

namespace DaisukeDaisuke\MyFirstPlugin;

use pocketmine\plugin\PluginBase;

class Main extends PluginBase{

}

次にpubfと手動で入力します。すると候補が出てくると思います。

<?php

declare(strict_types=1);

namespace DaisukeDaisuke\MyFirstPlugin;

use pocketmine\plugin\PluginBase;

class Main extends PluginBase{
    pubf
}

するとスニペットが展開されるので、大文字小文字間違えず1文字も間違えずににonEnableを入力します。
次にキーボードのtabキーを3回押します。するとカーソル位置がかっこの中に移動します。

<?php

declare(strict_types=1);

namespace DaisukeDaisuke\MyFirstPlugin;

use pocketmine\plugin\PluginBase;

class Main extends PluginBase{
    public function onEnable(): void{
        //カーソル
    }
}

次に、$this->と入力しましょう。すると候補が出ます。

<?php

declare(strict_types=1);

namespace DaisukeDaisuke\MyFirstPlugin;

use pocketmine\plugin\PluginBase;

class Main extends PluginBase{
    public function onEnable(): void{
        $this->
    }
}

次にgetLと入力してみましょう。するとgetLoggerが出るので、途中で入力をやめて、エンターtabを押しましょう!
すると補完されます!

<?php

declare(strict_types=1);

namespace DaisukeDaisuke\MyFirstPlugin;

use pocketmine\plugin\PluginBase;

class Main extends PluginBase{
    public function onEnable(): void{
        $this->getLogger()
    }
}

次に、->inを入力してみましょう!infoが補完されました!

<?php

declare(strict_types=1);

namespace DaisukeDaisuke\MyFirstPlugin;

use pocketmine\plugin\PluginBase;

class Main extends PluginBase{
    public function onEnable(): void{
        $this->getLogger()->info()
    }
}

次に、かっこの中に"を2つ入力しましょう!

<?php

declare(strict_types=1);

namespace DaisukeDaisuke\MyFirstPlugin;

use pocketmine\plugin\PluginBase;

class Main extends PluginBase{
    public function onEnable(): void{
        $this->getLogger()->info("")
    }
}

"の間に、好きなメッセージを入れてみましょう!

<?php

declare(strict_types=1);

namespace DaisukeDaisuke\MyFirstPlugin;

use pocketmine\plugin\PluginBase;

class Main extends PluginBase{
    public function onEnable(): void{
        $this->getLogger()->info("私の最初のプラグイン(大嘘)")
    }
}

関数呼び出しには忘れてはならないものがあります。行の終わりを表す、;です。
今は;がないので、読み込むとパースエラーが発生します。なので追加する必要があります。

キーボードまたはマウス、またはendで、行の終わりに移動し、;を追加します。

<?php

declare(strict_types=1);

namespace DaisukeDaisuke\MyFirstPlugin;

use pocketmine\plugin\PluginBase;

class Main extends PluginBase{
    public function onEnable(): void{
        $this->getLogger()->info("私の最初のプラグイン(大嘘)");
    }
}

これでもっとも単純なプラグインの完成です!

早速1枠目の方法でサーバーを起動しましょう!

こんな文章が出力されれば成功です!

[02:55:53.413] [Server thread/INFO]: Enabling MyFirstPlugin v0.0.1
[02:55:53.414] [Server thread/INFO]: [MyFirstPlugin] 私の最初のプラグイン(大嘘)

棒をたたくとメッセージを送るプラグイン

やはりpmmpは機能は少なくともゲームサーバーなので、ゲーム内に干渉したいですよね!
こんどは棒をたたくとプレーヤーにメッセージを送るプラグインを作りましょう!

まず、棒をたたいたことを検知するために、イベントの事前登録が必要です。
つまり、pmmpに「私イベント受け取れてこんなイベントの処理をもってますよ?」って報告しないと発生したイベントのシグナルを分けてくれないといった感じです。

まず、登録を行うためにはプラグインの拡張を行う必要があります。
この手順はpmmpで開発する上では、何回も行うことになるので、呪文として暗記した方がいいです。

次のコードがあるとします。

<?php

declare(strict_types=1);

namespace DaisukeDaisuke\MyFirstPlugin;

use pocketmine\plugin\PluginBase;

class Main extends PluginBase{
    public function onEnable(): void{
        $this->getLogger()->info("私の最初のプラグイン(大嘘)");
    }
}

class Main extends PluginBase{にのe{の間に移動し、<スペース>imp<エンター>と入力します。

<?php

declare(strict_types=1);

namespace DaisukeDaisuke\MyFirstPlugin;

use pocketmine\plugin\PluginBase;

class Main extends PluginBase implements{
    public function onEnable(): void{
        $this->getLogger()->info("私の最初のプラグイン(大嘘)");
    }
}

そのまま<スペース>List<エンター>を入力します。
すると自動でuse文が追加され、(イベントの)Listenerであることを宣言することができました。

<?php

declare(strict_types=1);

namespace DaisukeDaisuke\MyFirstPlugin;

use pocketmine\event\Listener;
use pocketmine\plugin\PluginBase;

class Main extends PluginBase implements Listener{
    public function onEnable(): void{
        $this->getLogger()->info("私の最初のプラグイン(大嘘)");
    }
}

ただ、これだとオレオレlistenerのように自称してるだけなので、pmmpに私イベント受け取れますよと報告しましょう。
$this->getLogger()->info("私の最初のプラグイン(大嘘)");の最後文字に移動し、キーボードのエンターをクリックします。

<?php

declare(strict_types=1);

namespace DaisukeDaisuke\MyFirstPlugin;

use pocketmine\event\Listener;
use pocketmine\plugin\PluginBase;

class Main extends PluginBase implements Listener{
    public function onEnable(): void{
        $this->getLogger()->info("私の最初のプラグイン(大嘘)");
        <カーソル>
    }
}

$this->と入力します。

<?php

declare(strict_types=1);

namespace DaisukeDaisuke\MyFirstPlugin;

use pocketmine\event\Listener;
use pocketmine\plugin\PluginBase;

class Main extends PluginBase implements Listener{
    public function onEnable(): void{
        $this->getLogger()->info("私の最初のプラグイン(大嘘)");
        $this-><カーソル>
    }
}

getSer<エンター>->と入力し、エンターを押します。

<?php

declare(strict_types=1);

namespace DaisukeDaisuke\MyFirstPlugin;

use pocketmine\event\Listener;
use pocketmine\plugin\PluginBase;

class Main extends PluginBase implements Listener{
    public function onEnable(): void{
        $this->getLogger()->info("私の最初のプラグイン(大嘘)");
        $this->getServer()->
    }
}

getPlugと入力し、2番目のgetPluginManagerを選びます。

<?php

declare(strict_types=1);

namespace DaisukeDaisuke\MyFirstPlugin;

use pocketmine\event\Listener;
use pocketmine\plugin\PluginBase;

class Main extends PluginBase implements Listener{
    public function onEnable(): void{
        $this->getLogger()->info("私の最初のプラグイン(大嘘)");
        $this->getServer()->getPluginManager()
    }
}

->rと入力し、registerEventsを選びます。sがある方です。

<?php

declare(strict_types=1);

namespace DaisukeDaisuke\MyFirstPlugin;

use pocketmine\event\Listener;
use pocketmine\plugin\PluginBase;

class Main extends PluginBase implements Listener{
    public function onEnable(): void{
        $this->getLogger()->info("私の最初のプラグイン(大嘘)");
        $this->getServer()->getPluginManager()->registerEvents()
    }
}

かっこ内に移動し、$this, $thisを入力します。呪文です。

<?php

declare(strict_types=1);

namespace DaisukeDaisuke\MyFirstPlugin;

use pocketmine\event\Listener;
use pocketmine\plugin\PluginBase;

class Main extends PluginBase implements Listener{
    public function onEnable(): void{
        $this->getLogger()->info("私の最初のプラグイン(大嘘)");
        $this->getServer()->getPluginManager()->registerEvents($this, $this)
    }
}

最後に関数呼び出しなので、;を文末に追加します。

<?php

declare(strict_types=1);

namespace DaisukeDaisuke\MyFirstPlugin;

use pocketmine\event\Listener;
use pocketmine\plugin\PluginBase;

class Main extends PluginBase implements Listener{
    public function onEnable(): void{
        $this->getLogger()->info("私の最初のプラグイン(大嘘)");
        $this->getServer()->getPluginManager()->registerEvents($this, $this);
    }
}

サーバーを起動し、エラーを吐かないこと(赤いメッセージ)を確認します。
これでちゃんとpmmpにイベントを受け取れることを報告できたので、実際のイベントの処理部や、イベントの種類を指定、追加します。

このコードで発生しうるエラーを一部紹介

Q:

 ParseError: "syntax error, unexpected token "}"" (EXCEPTION)
 syntax error, unexpected token "{"

A:
;をちゃんと追加したか確認してください
implementsの実装途中でやめてませんか?

Q:

ParseError: "Unclosed '{' on line 10" (EXCEPTION)

A: }を間違って消しちゃってます。}を適当に追加するのはやめましょう。事故の原因です。

Q:

ArgumentCountError: "Too few arguments to function pocketmine\plugin\PluginManager::registerEvents(), 1 passed in C:\Users\ESv87g9gvea4\Downloads\PocketMine-MP\plugins\MyFirstPlugin\src\Main.php on line 13 and exactly 2 expected"

A: $thisの数が少ないです。

Q:

ParseError: "syntax error, unexpected token "public", expecting "{"" (EXCEPTION)

A: {がないです

Q:

ParseError: "Unmatched '}'" (EXCEPTION) 

A: }が多すぎます

Q:

TypeError: "pocketmine\plugin\PluginManager::registerEvents(): Argument #1 ($listener) must be of type pocketmine\event\Listener, DaisukeDaisuke\MyFirstPlugin\Main given, called in C:\Users\ESv87g9gvea4\Downloads\PocketMine-MP\plugins\MyFirstPlugin\src\Main.php on line 13" (EXCEPTION)

A: これがない

 implements Listener

イベントを実装

その前に前提知識をいつくか。

Playerオブジェクト

  • pmmpでプラグイン開発をする上で、必ず出てくるphpオブジェクトです。
  • プレーヤーオブジェクトは1個が1人のオンラインプレーヤーに割り当てられています。
  • phpのオブジェクトの都合上、どんなにコピーしても同じプレーヤーなら同じplayerオブジェクトが取得されます。
  • プレーヤーオブジェクトを配列等に格納した場合、勝手にnullになることはありません。
  • ただし、プレーヤーがログアウトしてオフラインになるとプレーヤーオブジェクトは大半の機能を失い、$player->isOnline()のみ安全に実行することができます。それ以外は基本サーバがクラッシュします。
  • $player->isOnline()は最終手段であり、基本的にはプラグインはPlayerQuitEventでプレーヤーへの参照を消します。
  • なお、基本ユーザーが再ログインすると機能を失ったプレーヤーオブジェクトがもとに戻るとは考えない方がいいです。イベント等から再取得する必要があります。

イベントシステム

  • イベントの定義は特定のルールの関数の定義によって行われます。
  • イベントの登録をしていないクラスが勝手に呼ばれるといった超能力的なことはありません。
  • イベントは同時実行されることはありません
    • 同時実行ガードは不要です。
    • 2つのイベントを定義した場合、実質ランダムな順序で順番に実行されます。
    • イベントには優先度があり、所定の方法で優先度を上げたり下げたりすることで実行順番を制御する方法も用意 されています。
  • $this->getServer()->getPluginManager()->registerEvents($this, $this);は呪文です。
  • イベントオブジェクトは、各イベントによってさまざまな関数を持っています。

現在このようなコードがあります。

<?php

declare(strict_types=1);

namespace DaisukeDaisuke\MyFirstPlugin;

use pocketmine\event\Listener;
use pocketmine\plugin\PluginBase;

class Main extends PluginBase implements Listener{
    public function onEnable(): void{
        $this->getLogger()->info("私の最初のプラグイン(大嘘)");
        $this->getServer()->getPluginManager()->registerEvents($this, $this);
    }
}

関数を定義したいので、クラスのカッコの一番下で改行します。

<?php

declare(strict_types=1);

namespace DaisukeDaisuke\MyFirstPlugin;

use pocketmine\event\Listener;
use pocketmine\plugin\PluginBase;

class Main extends PluginBase implements Listener{
    public function onEnable(): void{
        $this->getLogger()->info("私の最初のプラグイン(大嘘)");
        $this->getServer()->getPluginManager()->registerEvents($this, $this);
    }
    <カーソル>
}

pubfと入力します。

<?php

declare(strict_types=1);

namespace DaisukeDaisuke\MyFirstPlugin;

use pocketmine\event\Listener;
use pocketmine\plugin\PluginBase;

class Main extends PluginBase implements Listener{
    public function onEnable(): void{
        $this->getLogger()->info("私の最初のプラグイン(大嘘)");
        $this->getServer()->getPluginManager()->registerEvents($this, $this);
    }
    pubf
}

1つ目は適当にします。tabを押し、

<?php

declare(strict_types=1);

namespace DaisukeDaisuke\MyFirstPlugin;

use pocketmine\event\Listener;
use pocketmine\plugin\PluginBase;

class Main extends PluginBase implements Listener{
    public function onEnable(): void{
        $this->getLogger()->info("私の最初のプラグイン(大嘘)");
        $this->getServer()->getPluginManager()->registerEvents($this, $this);
    }

    public function a(): void{
        
    }
}

2つめはイベント名を入れます。
今回は、アイテムを空中タップしたときのイベントが欲しいので、PlayerItemUseEventを使います

<?php

declare(strict_types=1);

namespace DaisukeDaisuke\MyFirstPlugin;

use pocketmine\event\Listener;
use pocketmine\event\player\PlayerItemUseEvent;
use pocketmine\plugin\PluginBase;

class Main extends PluginBase implements Listener{
    public function onEnable(): void{
        $this->getLogger()->info("私の最初のプラグイン(大嘘)");
        $this->getServer()->getPluginManager()->registerEvents($this, $this);
    }

    public function a(PlayerItemUseEvent): void{
        
    }
}

<スペース>$eventと入れます。

<?php

declare(strict_types=1);

namespace DaisukeDaisuke\MyFirstPlugin;

use pocketmine\event\Listener;
use pocketmine\event\player\PlayerItemUseEvent;
use pocketmine\plugin\PluginBase;

class Main extends PluginBase implements Listener{
    public function onEnable(): void{
        $this->getLogger()->info("私の最初のプラグイン(大嘘)");
        $this->getServer()->getPluginManager()->registerEvents($this, $this);
    }

    public function a(PlayerItemUseEvent $event): void{
        
    }
}

これがイベントの基本形です!

このイベントがどんな関数を持ってるかわからないので、pmmpのソースコードを見に行きましょう。
ctrlを押しながらPlayerItemUseEvent右クリック します。
するとソースコードに飛びます。

image.png

どうやらアイテムを取得できるようですね!

PlayerEventが気になるので、見に行きましょう!
ctrlを押しながらPlayerEvent右クリック します。

どうやらgetPlayerという関数があるようですね!いかにもplayerオブジェクトを取得できそうな名前です。
image.png

ソースコードから情報を得たので、Main.phpに戻り、プレーヤーオブジェクトを取得してみましょう!

カーソル位置をここに合わせます。

    public function a(PlayerItemUseEvent $event): void{
        <カーソル>
    }

$player = と入力します。

    public function a(PlayerItemUseEvent $event): void{
        $player = 
    }

PlayerItemUseEvent、変数名$eventからプレーヤーを取得しましょう。
$e<エンター>->と入力します。

    public function a(PlayerItemUseEvent $event): void{
        $player = $event->
    }

先ほど調べたgetPlayer関数を呼び出しましょう!
getP<エンター>と入力します。

   public function a(PlayerItemUseEvent $event): void{
        $player = $event->getPlayer()
    }

関数呼び出しの終わりには;が必要なので、追加します。

   public function a(PlayerItemUseEvent $event): void{
        $player = $event->getPlayer();
    }

メッセージを送ってみましょう。メッセージを送る関数は(Player)->sendMessage()です!

改行し、$p<エンター>と入力します。

    public function a(PlayerItemUseEvent $event): void{
        $player = $event->getPlayer();
        $player
    }

->sendmを入力します。

    public function a(PlayerItemUseEvent $event): void{
        $player = $event->getPlayer();
        $player->sendMessage()
    }

sendメッセージには文字列が必要なので、""を入力します。

    public function a(PlayerItemUseEvent $event): void{
        $player = $event->getPlayer();
        $player->sendMessage("")
    }

すきなメッセージを入力します。

    public function a(PlayerItemUseEvent $event): void{
        $player = $event->getPlayer();
        $player->sendMessage("pmmp好きな処理発表ドラゴン")
    }

関数呼び出しの終わりには;が必要なので、追加します。

    public function a(PlayerItemUseEvent $event): void{
        $player = $event->getPlayer();
        $player->sendMessage("pmmp好きな処理発表ドラゴン");
    }

複数のメッセージを送りたい場合は、複数回呼び出します!
文字の変数展開をしたくない場合は、7と同じ位置にある、'これで囲みます。@の位置にあるやつ「`」で囲むとコマンドが実行されて最悪パソコンが壊れるので絶対しないでください

<?php

declare(strict_types=1);

namespace DaisukeDaisuke\MyFirstPlugin;

use pocketmine\event\Listener;
use pocketmine\event\player\PlayerItemUseEvent;
use pocketmine\plugin\PluginBase;

class Main extends PluginBase implements Listener{
    public function onEnable(): void{
        $this->getLogger()->info("私の最初のプラグイン(大嘘)");
        $this->getServer()->getPluginManager()->registerEvents($this, $this);
    }

    public function a(PlayerItemUseEvent $event): void{
        $player = $event->getPlayer();
        $player->sendMessage("pmmpの好きな処理発表ドラゴン");
        $player->sendMessage("1位: \Closure::bind(fn() => なんか, \$packet, \$packet)();");
        $player->sendMessage('2位: HandlerListManager::global()->unregisterAll($listener);');
        $player->sendMessage('3位: $this->getScheduler()->scheduleRepeatingTask(new ClosureTask(function() : void{}), 20);');
    }
}

サーバーを起動し、opを付与し、ゲームモードを1にしてアイテムを空中クリックすると、メッセージが送信されます!
image.png

サーバーに同じパソコンのマインクラフトwin10エディションから入れない場合、インストーラーの管理者権限を2つとも許可したかどうか確認してください

この記事は以上です、お疲れさまでした。
次回は、数か月後、第3回企画、phpstromセットアップ編、第4回企画、すぐにコピペできるコード編、(未定)、上級者向けテクニック編でお会いしましょう。
それではよいソースコード漁りライフを!

さいごに

コードスニペット紹介

pubf: public function
pubsf: public static function
prof: protected function
prosf: protected static function
prif: private function
prisf: private static function
thr: throw new

エディタが参照するソースコードの更新

次のフォルダに移動します。

C:\Users\<ユーザー名>\Downloads\PocketMine-MP\composer

エクスプローラーのアドレスバーにcmdと入れ、コマンドプロンプトをこのフォルダで起動します。
次のコマンドを実行します。

..\bin\php\php.exe .\composer.phar upd

コマンドが完了すれば、エディタの参照するソースコードが更新済みです。
場合によってはvsocdeの再起動も必要です

次の記事を待ちきれない場合

server.mcbe.jpでpmmp歴8年自称プロである私がサポートします。
https://server.mcbe.jp/

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?