Minecraft commands from cronjob

For a minecraft mini-game I wanted to give all the players a special item at predefined times. In this case: every ten minutes the game lasts, the players who are still remaining are getting a special item.

Off course I could be searching for a bukkit plugin, but we are playing the vanilla for this one. So I decided to write a bash script which is called from a cronjob.

Before we start coding, there are a couple things to consider. I’m using the minicraft init script from the minecraftwiki. This script starts the minecraft server in a screen session called minecraft. The players can start this mini-game whenever they want and without me interfering. The cronjob should run when the game is started.

The other thing to consider are the available players. I would be nice if we could run the /list command in the screen session (which lists all the current players) and then only give those players the items. Unfortunately I haven’t found a way to get the output from a screen session. That said, it is possible to get the whole output from the screen session by enabling logging, but then the whole session is being logged (which could end up pretty big). So I decided to read the white-list.txt and send all of them the items. If a player is already left the game or doesn’t take part at the current game, the command just doesn’t do anything.

On that note, it’s time to start coding:

  1. Create a new bash file in your favorite folder (I’m using ~/bin/): nano ~/bin/mcminigame
  2. Tell which shell you want to use: #!/bin/sh
  3. This script is specifically for this mini-game, but it could be useable for other games too. So I decided to put the white-list file in a variable: FILE="/srv/minecraft_server/white-list.txt"
  4. The first thing we should do next is to check if the minecraft session is active. If it’s not active, it shouldn’t do anything.Screen has an option to list all the current session by using the -list parameter:
screen -list

Outputs:

There is a screen on:
 6556.compiler (07/31/2013 19:38:38 AM) (Detached)
 1 Socket in /var/run/screen/S-dvdheiden.

So we could check this list with the grep command for the existing of the minecraft session:

screen -list | grep "minecraft"

There are however some flaws with this. If a session called “minecraft_test” is active, grep will give a match on that one. Thankfully grep has the -w parameter, which tells grep to search for whole words only. If we want to use this in our script, we have to test the result. Grep has also another parameter which is useful for testing the result, the -q parameter which stands for “Quiet”. When using grep with the -q parameter the result can be used in an if statement.

So all this information leads to the following if statement:

if ! screen -list | grep -w -q "minecraft"; then
  minecraft session is available so execute code here
fi
  • The next step is to read the white-list file which we put in the variable FILE at the third step. Every line in the white-list file is one player, so we can read the file line by line.
while read line; do
  $line is the player
done < $FILE
  • Now we have the player names, we can send the command to the screen session: screen -S minecraft -X stuff "/give $line 1 1$(printf '\r')"

    This looks complicated, so I will split it up. First we open the screen session by the screen name with: screen -S minecraft. The -X parameter takes care of sending the command to the screen session. In this case we use the command stuff which sends the command to the process inside the screen session instead of the screen command mode. Then we call Mincraft’s /give command, print the players name, the data value and the number of items. In this case the player gets one stone block, for other blocks see the data values. At last we need the send the “enter” key for executing the command.

The script is now complete and despite the long explanation above, the script is pretty small:

#!/bin/sh
FILE="/srv/minecraft_server/white-list.txt"
if ! screen -list | grep -w -q "minecraft"; then
while read line; do
screen -S minecraft -X stuff "/give $line 1 1$(printf '\r')"
done < $FILE
fi

The last step is adding it to the cronjob and let it run for every X minutes.

There’s one flaw remaining: when the game starts the cron should be activated. I made a control panel in which they can start games, which also adds the cronjob. If you want to know how to adds cronjobs from a bash file, see this post.