Minecraftは、私が最も興奮したプログラムの1つです。(Microsoftが最近買収した)Mojangによって開発されたオープンワールドゲーム、つまりサンドボックスゲームです。Minecraftは、創造的な表現のためのキャンバスを広げてくれますし、最近は違ったゲームの攻略法をいくつか試していますが、それでも私の興味は尽きません。
Minecraftで大邸宅を建てた1人として、ある旅へ読者のみなさんを連れ出すとともに、現実世界のアラームシステムでセキュリティを高める方法を紹介します。説明したいことはたくさんあるので2回に分けて、かつみなさんが自分でもなにかしらを発掘できるように本筋から離れた部分はいくつか残しておきたいと思います!
この記事のコードはここにあります。
Minecraftのプログラミング特訓コース
Minecraftは、2つのシンプルなアイデアの組み合わせから始まりました。1つは、プレーヤーが地図上で資源を見つけ、それを収穫するというもの。これらの資源、たとえば食品、木材のようなものは地上ですぐ見つかるものです。一方、金や石のような資源は発見するのにちょっとした努力が必要です。
これが、(Minecraftの)“mine”の由来です。資源でレッドストーンと呼ばれるものがあります。レッドストーンは地下深くにあって、ほかの資源を司る存在です。レッドストーンを獲得して地面に配置すると、回路基板の裏面に付けた銀色のコードに似た働きをします。ゲーム内では電池や電源に似た、いろいろな形態を取る電源エミッターでもあります。
獲得した資源を使用して、プレーヤーは家を建てたり、食べ物を調理したり、仮想回路を組み立てたりできます。これが“craft”の由来です。
私は「Zombies and Binary」というカンファレンスで、2つの名前の由来と基本回路、プログラミングについて講演しました。最近「php [tek] 2016」でもプレゼンしています。「FluentConf 2016」で講演したJavaScriptをテーマにした内容については、このYouTubeの動画を見てください。
広々としたMinecraft大邸宅を作りあげたと想像してください…
さて、この大邸宅の玄関のドアをしっかり閉めたいとします。玄関のドアが開いているかどうかを確認する方法が必要です。確認するには、レッドストーン、コンパレーター、コマンドブロックと呼ばれるものを使用する必要があります。
コマンドブロックに接続したスイッチがあるのに気づいたかもしれません。スイッチは電源の一種でコマンドブロックにいくらか電力を提供するので、ドアが開いているか、チェックの実行が可能です。このあとすぐに、この電源を自動化します。
コマンドブロックは、サーバーコマンドを格納できるプレースホルダーです。サーバーのコマンドは(サーバー管理者かシングルプレーヤーモードなら)プレーヤーとしてあらゆることができます。Amazon Dashボタンのように、ただボタンを押すだけでコマンドを1つ実行できます。
開いているドアに対して、コマンドブロックのテストをします。Minecraftの地図は座標に基づいていて、テストをするドアがある場所の座標を示す必要があります。分かりやすくするため、ドアの座標を191 67 -194とします。(開いている木製ドアの)テストコマンドは次のようになります。
/testforblock 191 67 -194 wooden_door 3
現在の地図の座標を表示するには、fn+altキー+F3キー(Mac)もしくはF3キー(Windows)を使います。ドアを配置したい場所まで進み、コマンドで座標を入力してください。
Minecraftでは、異なるブロックには(それがクラフトしたものか、自然のものかに関わらず) 固有のブロック名があります。wooden_doorは、オーク材のドアに固有のブロック名です。3はドアの向きを参照するものなので、もし異なる向きにドアを配置したい場合、地図上では違う情報が表示されます。その場合は、希望した向きになるまで0から3を入力してください。
テストによって合致するブロックを発見したら、2個目のコマンドブロックを表示するのにメッセージを送信します。スイッチを動かしてもドアが閉まったままなら特に変化は感じられません。しかし、ドアを開けたとき(そして開けるドアの向きのテストが合致したとき)、このような確認ができます!
これで開いているドアをチェックする方法が分かりました。しかし、このチェックを手動で実行する間、ただ突っ立っていたくはありません。無限ループに値するもの、または水晶時計の電子的なものを設定します。
これを可能にするにはコマンドブロックを2つ使って、このように配置します。
注意:各コマンドブロックにボタンを取り付けたので、それぞれのブロックでコマンドを実行できることに注目してください。これらのボタンは電源、つまり接続されているブロックに短時間、電流のスパイクを与える機能もあります。
マップ座標の相対的な定義もできます。つまり、コマンドブロックの近くの座標を参照したいとき、~-1 ~ ~+1で設定できます。これはコマンドブロックのX座標が-1、Y座標は同じ、Z座標は+1という意味です。
この配置で、一番上のコマンドブロックのすぐ下にレッドストーンブロックを設置します。
/setblock ~ ~-1 ~ redstone_block
そしてエアブロックが上に来るように下のコマンドブロックを配置します。
/setblock ~ ~+1 ~ air
レッドストーンブロックは電源としても機能します。この配置にはおもしろい副次的効果があります。一番上のブロックのすぐ下にレッドストーンブロックを配置すると、レッドストーンブロックは、最初に下のコマンドブロックに電力を供給します。その後、上部のコマンドブロックにも電力を供給するのです。
一方、下のコマンドブロックは、レッドストーンブロックを遮断します。こうして上のコマンドブロックは(下に置かれたレッドストーンブロックから)新しい電力信号を得て、下に置かれたコマンドブロックからは遮断されるので、最初から再び循環を始めます。
これが先ほど述べた無限ループにつながっていきます。ループはサーバーの再起動まで続き、クリエイティブモードでプレイ中であればレッドストーンブロックを壊しても、すぐに新しいものが作成されることが分かります。
デフォルト設定では、コマンドブロックのアクションはログに残り、サーバー上のメッセージのトリガーとなります。 これらは、2種類のコマンド/gamerule logAdminCommands falseと/gamerule commandBlockOutput false(マップごとに1度入力する)で無効にできます。
電源として時計とテスト中のコマンドブロックを直接つないでいる場合、1秒間に何度もテストされ、ドアが開いたとき即座にフィードバックが得られます!
Minecraftの新しいバージョンでは、自家発電と内部循環ができるコマンドブロックがあります。そのコマンドブロックでは、時計なしで繰り返しドアチェックが可能です。古いバージョンのMinecraftを使っている場合、特にmodパックの場合は、時計を自分で作る必要があります…
また、ドアを閉めているときは現実世界のアラームを無効にできますので、知っておくと便利です。そのためのインバーターの使用もできます。 閉じているドア (負の値)を真の値に変更することを考えると、while (true) if (!$doorOpen) print…とプログラミングで入力するのとほぼ同じです。
PHPでログファイルを監視する
この項で説明する方法はすべて複雑で、変更履歴をPHPで見ていく力がなければ役に立ちません。ドアが開いたときに「聞く」方法、そしてPHPに応じる方法が必要になります。
幸いなことに、ウィスパードメッセージ(whispered messages)がすべて記録されます。ログファイルを監視し、解釈する方法が分かれば、必要なすべての情報が把握できるはずです。
Packagistのクイックサーチでは、そのタスクに耐えられるファイル監視ライブラリーを提供しています。次のようにするとインストール可能です。
composer require yosymfony/resource-watcher
インストールが終わったあとは、ログファイルを監視するためのスクリプトを作ります。Symfony Finderインスタンスを作成して、Minecraftのログが格納されているディレクトリを指定します。
require __DIR__ . "/vendor/autoload.php";
use Symfony\Component\Finder\Finder;
$path = "/path/to/Application Support/minecraft/logs";
$finder = new Finder();
$finder->files()
->name("*.log")
->depth(0)
->in($path);
Application Supportへのパスはそれぞれ異なります(通常、アカウントに関連付けられているLibraryフォルダー内にあります)。ただしポータブルバージョンのMinecraftを使用している場合は、Logsフォルダーを見つけるまで少し探す必要があるかもしれません。
このFinderインスタンスで指定したのと同じディレクトリ内の*.logファイルに、ファイル監視リストを絞り込めます。メソッドの名前ははっきりしているので、ほかのアプリのための条件を広げられます。
次にキャッシュファイルと、監視インスタンスの定義が必要です。
use Yosymfony\ResourceWatcher\ResourceCacheFile;
use Yosymfony\ResourceWatcher\ResourceWatcher;
$cache = new ResourceCacheFile(__DIR__ . "/cache.php");
$watcher = new ResourceWatcher($cache);
$watcher->setFinder($finder);
while(true) {
sleep(1);
$watcher->findChanges();
// ...respond to changes
}
このスクリプトは実行時間の長いプロセスとして動作します。つまり、ファイルの変更状況を監視したいのですが、その間隔は不定期なのです。それで無限ループを作成し、常にファイルの変更を検出できるようにします。
多少の時間ならsleepできます。私は1秒で十分だと分かりましたが…
監視ライブラリーで3種類の変更、つまりファイルの作成、削除、更新を確認できます。このうち更新だけを注視します。
while(true) {
sleep(1);
$watcher->findChanges();
// ...respond to changes
$changes = $watcher->getUpdatedResources();
if (count($changes) > 0) {
$first = $changes[0];
$lines = file($first);
for ($i = count($lines) - 1; $i > -1; $i--) {
if (stristr($lines[$i], "CHAT")) {
if (stristr($lines[$i], "closed")) {
print "closed!";
}
if (stristr($lines[$i], "open")) {
print "open!";
}
break;
}
}
}
}
新しいチャットメッセージがログファイルの最後に追加されますので、ログファイルが変更されているかどうかをチェックしたいときは (通常ログファイルは1つのみです)、ログファイルを数行に分割しファイルの下から上に向かって各行を確認します。
ログの行にCHATが含まれているなら、それがチャットメッセージだと仮定できます。また、openやclosedが含まれていれば、それは自分たちが作成した回路によるものだと推測できます。
開閉に関するイベント通知に「ユニークな」メッセージフォーマットを使用するのも大歓迎です。私が個人的に選んだメッセージは単純ですが、abuseとambiguity(ほかの誰かが「開けて」と私にささやいてきたときなどに使います)。ただし、基本原則はどれも同じです。
この内容は実験の途上に過ぎません。次の記事では、Arduinoベースのアラーム回路を構築する方法、そしてそれをスクリプトにつなげる方法を紹介します。最後の結果は、自動ドアを備え現実世界のアラームが付いたMinecraft大邸宅の完成です。
(原文:PHP, Arduino And… Minecraft? Combining Minecraft with PHP!
[翻訳:皐月弥生]
[編集:Livit]