PHP
Article

PHP, Arduino And… Minecraft? Combining Minecraft with PHP!

By Christopher Pitt

PHP, Arduino, and... Minecraft?

IoTWeek_Gray

It’s IoT Week at SitePoint! All week we’re publishing articles focused on the intersection of the internet and the physical world, so keep checking the IoT tag for the latest updates.

Some of the most interesting programming I’ve done has been in Minecraft. It’s an open-world, sandbox game developed by Mojang, (recently acquired by Microsoft). Minecraft began as a canvas for creative expression, and while I do very different things in it these days, it still is that for me.

I’m going to take you on a journey, as we build a Minecraft mansion, and then secure it with a real-world alarm system. There’s quite a bit of ground to cover, and though I plan for this to be a two-part series, I’m going to have to leave some of the tangential details for you to discover!

You can find the code for this tutorial at https://github.com/sitepoint-editors/tutorial-php-arduino-and-minecraft

Crash Course in Minecraft Programming

Minecraft began as the combination of two simple ideas. The first is that players can harvest resources from the map in which they find themselves. Some of these resources, like food and wood, are common above ground. Others, like gold and stone, require a bit of virtual elbow-grease.

This is where the “mine” (in Minecraft) comes from. One of these resources is called Redstone. It’s found deep underground, and it’s a conductor of sorts. When harvested and placed on the ground, it resembles the silvery lines on the flip side of circuit boards. There are also power emitters, similar to batteries or mains power, which take many forms in the game.

In-game screenshot of Redstone

Using these harvested resources, players can build dwellings, cook food and even wire up virtual circuitry. This is where the “craft” comes from.

I talk about all of this, as well as basic circuitry and programming, in my conference talk Zombies and Binary. I presented it most recently at php[tek] 2016, but the recording was lost. Here’s a JavaScript-themed version, from FluentConf 2016: https://youtu.be/APJRBZUxADQ.

Imagine we’ve created a sprawling Minecraft mansion…

In-game screenshot of mansion

Now, imagine we want to secure the front door of said mansion…We need a way to check whether the front-door has been opened. To do this, we need to use Redstone, something called a Comparator, and another thing called a Command block:

In-game screenshot of testing for block

You may notice the switch I’ve connected to the Command block. Switches are one kind of power source, and this one will provide some power to the Command block so that it can perform the open door check. We’ll automate this power source in a bit…

Command blocks are placeholders which can contain a single server command. Server commands are anything you as a player can do (provided you are a server admin or in single-player mode). They’re like Amazon Dash buttons, in that they can be given a single command to run, at the push of a button.

We’re going to make the Command block test for an open door. Minecraft maps are coordinate-based, which means the test needs to include coordinates for where the door will be placed. For argument’s sake, let’s say the door is at 191 67 -194. The command for the test (of an open wooden door) will then be:

/testforblock 191 67 -194 wooden_door 3

You can find your current map coordinates with fn + alt + F3 (for Mac) and F3 (for Windows). Walk to the block where you’ll place the door, and enter those coordinates in the command.

Different Minecraft blocks (whether crafted or naturally occurring) have unique block names. wooden_door is the unique block name for an Oak door. 3 is a reference to the orientation of the door, so it might be different in your maps if you place your door in a different orientation. If so, try 0 through 3 until you get the desired result.

We’ll make the second Command block whisper a message back to us to indicate when the test has found a matching block. When we flick the switch, and the door is still closed, we should see nothing. But when we open the door (and the test matches the open door’s orientation), we should see confirmation of this!

In-game moving image of testing for a block

Now we have a way to check for an open door. We don’t want to be standing around, to manually run this check though. Let’s set up the programming equivalent of an infinite loop, or the electronic equivalent of a crystal clock.

For this we need two Command blocks, arranged like this:

In-game screenshot of clock

Notice I’ve attached a button to each Command block, so that I can run their commands. These buttons also act as a power source, giving a brief power spike to the blocks they’re connected to.

Map coordinates can also be relatively defined. That is, if you need to reference coordinates nearby the Command block, you can use ~-1 ~ ~+1 to mean the Command block’s x coordinate minus 1, the same y coordinate, and it’s z coordinate plus 1.

In this arrangement, we want the top Command block to place a Redstone block just below it:

/setblock ~ ~-1 ~ redstone_block

…And we want the bottom Command block to place a block of air above it:

/setblock ~ ~+1 ~ air

Redstone blocks also act as a power source. This arrangement has an interesting side-effect. When the top block places a Redstone block below itself, the Redstone block gives power first to the bottom Command block. It then gives power to the top Command block.

In the meantime the bottom Command block has removed the Redstone block. Since the top Command block got a new power signal (from the Redstone block it placed) and the block was then removed by the bottom Command block, it starts the cycle over again.

This leads to the infinite loop I spoke about. The loop will persist through server restarts, and if you’re in creative mode you’ll be able to break the Redstone block and see new ones created instantly.

In-game animated image of working clock

By default, these Command block actions will be logged and will trigger messages on the server. You can disable these with a couple commands (which you only have to enter once per map): /gamerule logAdminCommands false and /gamerule commandBlockOutput false.

If we take power from the clock, and direct it into the testing Command block, the test will run many times a second, giving immediate feedback when the door is opened!

Newer versions of Minecraft allow Command blocks to power themselves and even repeat themselves. With that, it’s possible for the door check to repeat without the clock. If you’re using an older version of Minecraft, especially when using mod packs, you may still need to make the clock yourself…

In-game animation of working door, opening and closing

It’s also useful to know when the door has been closed, so we can turn the real-world alarm off. For that we can use an inverter (think of it as turning the closed door (false value) to a true value, in much the same way as we would in programming: while (true) if (!$doorOpen) print....

In-game screenshot of inverter

Watching Log Files with PHP

All of this is pretty and useless without the ability to see these changes in PHP. We need a way to “hear” when the door has been opened, and react in PHP.

Fortunately, the whispered messages are all logged. If we can figure out how to watch and interpret the log files, we should have all the information we need…

A quick Packagist search provides a file watcher library which looks like it’s up to the task. We can install it with:

composer require yosymfony/resource-watcher

After that’s done, let’s make a script to watch the log files. We begin by creating a Symfony Finder instance, and pointing it at the directory in which the Minecraft logs are stored:

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);

The path to Application Support will be different for you – it’s usually in the Library folder associated with your account. You could also be using a portable version of Minecraft, so you’ll just have to search around a bit, until you find the logs folder.

This Finder instance narrows the file watch list to *.log files in the same directory as the one we’ve specified. The methods are clearly named, so you can expand the criteria for other applications.

Next we need to define a cache file, and a watcher instance:

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
}

This script acts as a long-running process. That is, we want to watch for changes to files, for an indeterminate amount of time. So we create an infinite loop, and use it to constantly probe for file changes.

You can sleep for more or less time. I found 1 second was good enough for me…

The watcher library provides methods for three kinds of file changes: creation, deletion and updates. We only care about the updates:

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;
            }
        }
    }
}

New chat messages are appended to the bottom of the log file, so we need to check if any log files have been modified (we expect only one log file), split the log file into lines and check each line from the bottom of the file to the top.

If we see a log line containing CHAT, we can assume it is a chat message. If it also contains open or closed, we can assume it is caused by the circuit we created.

Animated image of PHP and Minecraft working together

You’re welcome to use more “unique” message formats for open/close events. The approach I’ve chosen is simple but open to abuse and ambiguity (like if someone else whispers “open” to me). The underlying principles are the same though.

This is only half of the experiment. In the followup post we’ll look at how to build an Arduino-based alarm circuit, and connect it to this script. The end result will be an automated, real-world alarm for our Minecraft mansion.

If you’ve enjoyed this and/or have questions, please let us know in the comments!

  • janw_oostendorp

    Neat Idea.
    If you are doing something like this, you should use default textures/UI It’s quite distracting.

    • Chris

      Thanks. Sorry about the textures.

    • S. Clever

      I disagree. I like this texture pack much better than the default Minecraft texture pack. Nice article!

  • Clark Winkelmann

    Nice. Does it work in multiplayer too ? (That’s where it would be useful for real) What about when you are not connected to the server, the command blocks need to be close to the door to be active if someone walks by I believe ?

    • Chris

      It does work on multiplayer, and you may be right about the proximity (due to chunk unloading in the game). Perhaps they could be buried underground… :)

      • Clark Winkelmann

        If we talk about security, you need to be sure nobody breaks blocks around the door or edits the command blocks. You need to build a vault with commands blocks inside that check for any wall break :D Well, I know what to do after reading the future second part xD

        • Chris

          Most multiplayer servers I’ve been on have set players to survival or adventure mode, which (as far as I can remember) means you can’t edit command blocks or break bedrock. A bedrock room would suffice…

Recommended

Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!

Get the latest in PHP, once a week, for free.