I enjoy Minecraft, as I'm sure many of you do, and I especially enjoy collaborating on projects with my friends, so I did the only logical thing I could think of and set up my own server using a spare computer. The only problem is that the friends I play Minecraft with live on the other side of the country from me, so it's sometimes hard to coordinate times when we can all get online together. The logical conclusion, then, was for me to set up a notification system to let me know when my friends get online, and since I'm sure that others of you are in the same boat, I'm here to share with you the process and the results of getting these notifications working.
Step 1: What You Will Need
To replicate my setup, you'll need:
- A Linux-based Minecraft server (I use Debian-based machines throughout)
- An email address to send notifications from (this Instructable assumes a Gmail address)
- The ssmtp package
Additionally, you may need:
Step 2: Configure Ssmtp
Everything we're going to be doing will be done directly on the Minecraft server. Either connect a monitor, mouse, and keyboard to your server or log in to it from your main computer using SSH. (Setting up SSH, while very useful, is beyond the scope of this Instructable.)
The ssmtp package is pretty basic both in use and in configuration. To install ssmtp on a Debian-based system such as Ubuntu, Linux Mint, or Elementary (among many others), simply open up your terminal of choice (if you're using Guake, you can just drop a terminal down by hitting F12) and type
sudo apt-get install ssmtp
After the package is installed on your Minecraft server, edit its configuration using your text editor of choice with the following (substituting your editor of choice for vim).
sudo vim /etc/ssmtp/ssmtp.conf
Unless you're logged in as root on your server, you'll need to use sudo when editing this file so that you can write changes to it.
Note: if you're running your Minecraft server headless (without a monitor attached), you'll have to use a command-line text editor such as vim/vi, nano, or [*shudder*] emacs, instead of a GUI application like Gedit or Notepad.
In the config file, you'll need to make the following changes:
The root parameter should be set to the full email address you're going to use, such as email@example.com
The mailhub parameter should be set to smtp.gmail.com:587
Your hostname and AuthUser should also be set to the email address used for root.
AuthPass should be set to your email password
Finally, UseSTARTLS should be set to YES
Once all of this information has been entered, save your changes (in vim, this would be done with <esc>:wq) and exit. Now you should be able to send an email from the command-line by invoking ssmtp with the following syntax:
sudo ssmtp firstname.lastname@example.org
Hit enter, then type a test message and end it with Ctrl-D
(Using ssmtp doesn't require root privileges, but if you're like me, /usr/sbin isn't in your $PATH and it's easier just to use sudo than to enter the full path.)
Once you've got ssmtp working, we can move on to the meat of this project.
Step 3: Finding Connected Players and Making a Basic Notifier
To find out if any players are connected to our Minecraft server, it turns out that we can use a package that's already installed on our machines, lsof. lsof lists open files, and since we're using Linux, where everything is a file, this includes network connections. If you just run lsof without any flags, you'll get many many pages of output, but that can be filtered down. The -i flag specifies network connections, but using that by itself is likely to still produce too many results, even on a single-use server. This can be narrowed down even further by specifying that we're looking only for TCP connections on port 25565 (this will differ if you're running your Minecraft server on a non-standard port), but even that will produce results even if nobody is connected to the server.
Just to find out what the output looks like right now, so we know how we need to narrow things down, let's run the command we have so far.
The output of this will look something like this (provided nobody is connected):
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 11504 me 30u IPv6 4041229 0t0 TCP *:25565 (LISTEN)
Let's focus in on that last column, though, since it seems to be the most important. Using awk, we can filter out everything except that last column. Doing that, if someone were connected, we'd see something like the following:
Luckily, lsof has a flag that lets us further filter our results. Since we're only interested in connections with the status of ESTABLISHED, we can now find if anybody is connected to our server by running
lsof -iTCP:25565 -sTCP:ESTABLISHED
Now we can do some basic command-chaining, using &&, to send an email when somebody is connected to the server.
Our simple notifier now looks like this
lsof -iTCP:25565 -sTCP:ESTABLISHED && echo "Players online" | /usr/sbin/ssmtp email@example.com
We can now open up our crontab, using crontab -e, and create a new line like so
*/5 * * * * lsof -iTCP:25565 -sTCP:ESTABLISHED && echo "Players online" | /usr/sbin/ssmtp firstname.lastname@example.org
Now, we could just stop here, with a cron job that fires every five minutes, checks for players connected to our Minecraft server, and sending out an email if it finds any, but the way we have it set up now will send a notification every five minutes as long as there are players connected.
Let's make that work a little better, shall we?
Step 4: Defining Some Logic
Our little one-liner from the last step is a nice start, but it's got some problems. We don't want it to tell us that there are players online every five minutes (or whatever increment we specify); it would be much better for it to tell us there are players online now only if there hadn't been the last time it checked. What's the easiest way to record whether there were players online or not the last time the script checked? We can do some simple output-redirection to create a file that says whether or not there are players online.
So now that we know what we want to do, let's write some pseudo-code. Pseudo-code is basically a set of human-readable instructions that define the logic of a program. It's the best place to start when you're writing a new program, or even when you're stuck on a bug while working on an existing program.
Here's what we want our script to do:
- Check if there's a players file that isn't empty
- if there is a non-empty players file, do nothing
- otherwise, empty or delete the players file
- check if there are players online
- if so, send out a notification
- also, populate the players file for the next check
Now that we have the logic defined, let's make this into a script.
Step 5: Scripting Our Logic
While you could write this script in any number of ways, the simplest is just to use bash. I'm using the -s flag for test (though for the look of it, I'm using [ ] rather than test—they're the same thing and accept the same flags) because it checks not only if a file exists but also if it is non-empty. The reason is that it takes fewer lines of code to effect the same results by using the > operator for simple output redirection, writing nothing to the .players file (and thereby making it empty) if the lsof invocation produces no output, rather than having to invoke rm to remove it completely.
After you've written the script, don't forget to make it executable by changing its permissions with chmod a+x (if it's not executable by the all group, your crontab may not be able to automate the task). Finally, pop that puppy into your crontab in place of our original notifier, and the next time one of your friends logs in to your server, you'll get a message telling you about it.
Step 6: Making It Extra Fancy
If you're like me, you probably always have your email open or are checking your phone constantly to make sure you don't miss anything, but you can also have your script text your phone by using the appropriate SMS/MMS email gateway for your carrier. It used to take a little magic to find out what your gateway was, but nowadays, there's a GitHub repo with all that information. You can find that repo here.