Jump to content

  • Curse Sites
Become a Premium Member! Help
Latest News Article

[Multi World] Linux Minecraft server control script


  • Please log in to reply
242 replies to this topic

#1

sandain
    sandain

    Zombie Killer

  • Members
  • 184 posts

Posted 09 January 2011 - 01:29 AM

I've been using various versions of the following script on my Debian and Ubuntu servers for the past couple of years, and I am rather satisfied with the way that it works.  I thought I would share it with the community in hopes that it would be found useful by others.


Features
  • Run multiple Minecraft worlds.
  • Supports CraftBukkit in addition to the standard Mojang server distribution.
  • Users automatically notified of important server events.
  • Keep track of users logged into the world servers.
  • Display a Message Of The Day to users logging into a world server.
  • Start, stop, and restart single or multiple worlds.
  • LSB-compatible init script, allows for seamless integration with your server's startup and shutdown sequences.
  • Map worlds using the Minecraft Overviewer mapping software.
  • Backup worlds, and remove backups older than X days.
  • Update the server software and installed addons.
  • Send commands to a world server from the command line.
See Usage for a description on how to use these features.


Download
Save the file as "minecraft_server", without the quotes.

Sourceforge:  http://svn.code.sf.n...inecraft_server
Pastebin: http://pastebin.com/iKs0Kqgm

wget http://svn.code.sf.net/p/mcshellscript/code/trunk/minecraft_server


Last Update
February 28, 2013


Change Log
  • Fix the detection of required programs.  Error messages should now display correctly if a program is found to be missing.
  • Fix the permissions for the screen tty using Montoya's patch.
  • Add the logrotate command to the script for rotating the log file using a modified version of Zanix's patch.
  • Search the world folder for an overviewer-settings.py file for custom mapping settings for the world using Zanix's patch.
  • Use the update infrastructure to manage the Minecraft client download using Zanix's patch.
  • Catch banned players logging off of the server using Zanix's patch.
  • Add support for Minecraft Overviewer and drop support for c10t and Pigmap.
  • Remove support for mcsuperserver.py, it is buggy and does not have an update for Minecraft 1.4.
  • Remove support for user and admin commands.  They no longer work with Minecraft 1.4.
  • Use Paul Andreassen's mcsuperserver.py to launch servers on demand as recommend by Culfri.
  • Add support for the Pigmap mapping software.
  • Added Zanix's backup patch.
  • Add a more descriptive error for when the server fails to start.
  • Fix an issue with wget not being able to download CraftBukkit at its current address (was breaking on the &).
  • Once again update the CraftBukkit download location to point to their latest release.
  • Add a separate variable for admin level user commands, but just give them access to the motd for now.
  • Recognise admins attempting to run a command.
  • Update the CraftBukkit download location to point to their latest stable build (fixes 1.0).
  • Add an IP address field to the worlds.conf file, blank by default.
  • Add the option to utilize a mirror image of a world for use in ramdisk configurations.
  • Modify init info to include support for chkconfig.
  • Add a lock file when running under RedHat/CentOS to fix shutdown issues (found by swallowtail23).
  • Display a message prior to displaying a world's screen about how to exit that screen.
  • Fix a bug in detecting the process ID of Screen when there are very similar world names (found by Tachdelan).
  • Fix mapping of the Nether when using CraftBukkit.
  • Update the CraftBukkit download location to point to their latest stable build (fixes beta 1.8).
  • Simplify the server type selection code as suggest by hexparrot.
  • Verify the download of c10t.
  • Add /help and /motd user commands.
  • Follow symbolic links when creating tar archives during a full backup.
  • Make the auto restart on SEVERE server event optional.
  • Simplify the Nether detection method, fixing the mapping of the Nether in 1.6.
  • Print a message if running the script as the wrong user.
  • Add current version detection for c10t download.
  • Fix c10t download.
  • Add support for CraftBukkit.
  • Add an option to connect to the Screen holding the world's console.
  • Restart the server when a SEVERE server event is caught.
  • Fix mapping of Nether worlds with c10t.
  • Allow spaces in addition to tabs in the worlds.conf file.
  • Allow the script to run from a user account.
  • Add the watch command line option to allow the server admin to watch the log file.
  • Add options to route lib-notify output to the correct user and display.
  • Make sure the server.log file exists prior to starting the log processor.
  • Allow comments in the worlds.conf file.
  • Be more verbose when doing updates to the server software.
  • Add a Message of the Day (MOTD) that is whispered to users when they log on.
  • Fix lib-notify output.
  • Remove the time from backup files, instead use a counter for multiple backups in the same day.  This should fix issues with file systems that don't like using a colon in the filename.
  • Output the number of online users when the scripts status command is given.
  • Fix 32/64 bit detection (used for updating c10t).
  • Add initial log processing.  Keep track of users logging in and out.
  • Make the script use the same world names as Minecraft.
  • Add error checking to calls to wget and screen.
  • Add backup duration variable and logic.  Backups older than X days are now removed when new backups are created.
  • Directories are now created properly when maps are first created with c10t.
  • Add send option, to send a command to the world server.
  • Add an infrastructure for updating addons, and add c10t to the update routine.
  • Add force-stop and force-restart options to kill a world server process after attempting a clean shutdown.  This will allow admins to stop locked servers more easily.
Installation
To get your server to run the script on startup, and cleanly down the server on shutdown, you need to copy the script to /etc/init.d, set execute permissions on the file, and instruct the system to use the script on startup and shutdown.  The following commands will work in Debian and Ubuntu like environments, ymmv in others.
sudo cp minecraft_server /etc/init.d/minecraft_server
sudo chmod 755 /etc/init.d/minecraft_server
sudo update-rc.d minecraft_server defaults

For security reasons, the script uses a user account named minecraft rather than root.  As such, you need to create the user before using this script:
sudo adduser minecraft

If the Minecraft server software is not located when the server start command is issued, the software will be downloaded to the proper location: /home/minecraft/minecraft_server/minecraft_server.jar


Requirements
I've made an attempt to utilize only features that are normally installed in most Linux and UNIX environments in this script, but there are a few requirements that this script has that may not already be in place:
  • Java 6 JDK - The Minecraft server software requires this.
  • Perl 5 - Most, if not all, Unix and Linux like systems have this preinstalled.
  • GNU Screen - Allows the script to run the Java process as a background daemon and send commands to the server.
  • GNU Wget - Allows the script to download software updates via the internet.
  • rdiff-backup - Allows the script to efficiently run backups.
  • Iptables - Although not explicitly required, a good firewall should be installed.
If you are running Debian or Ubuntu, you can make sure that these are installed by running:
sudo apt-get install openjdk-6-jdk perl screen wget rdiff-backup iptables


Mapping Software
The script now uses the Minecraft Overviewer mapping software to generate maps of your worlds.  You can download premade binaries for supported systems (Debian/Ubuntu, CentOS/RHEL/Fedora), or build your own binary from source if needed.


Multiple Worlds
The script can handle running multiple Minecraft world servers, just add each server to the /home/minecraft/worlds.conf file that will be generated on the first run.  Do not include the IP address information if it is not needed.

Example worlds.conf file for two worlds named alpha and beta and the ports that they run on.  This file will be generated if missing.

Note: The world name should not contain a space.  Leave the ip address blank if it is not needed.

# Minecraft world configuration file
# <world> <port> <ip>
alpha 25565
beta 25566
gamma 25567
delta 25568
epsilon 25569


Firewall / NAT
If you have a firewall installed on your computer, or a router using NAT installed in your network, you will need to route some ports to your server.  Instructions on how to accomplish this are beyond the scope of this post, but here are some things you will need to know:
  • The default port for the Minecraft server is: 25565.
  • If you wish to run multiple world servers using this script, you will want to open a range of ports (for example 25565 - 25575).
If you are using iptables, and you should be, here is a very basic ruleset that you can use.
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]

# Handle loopback addresses
-A INPUT -i lo -j ACCEPT
-A OUTPUT -o lo -j ACCEPT

# Allow outbound packets if state related, and inbound if established
-A OUTPUT -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Drop stealth scans
-A INPUT -i eth0 -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE
-A INPUT -i eth0 -p tcp -m tcp --tcp-flags SYN,FIN SYN,FIN
-A INPUT -i eth0 -p tcp -m tcp --tcp-flags SYN,RST SYN,RST
-A INPUT -i eth0 -p tcp -m tcp --tcp-flags FIN,RST FIN,RST
-A INPUT -i eth0 -p tcp -m tcp --tcp-flags ACK,FIN FIN
-A INPUT -i eth0 -p tcp -m tcp --tcp-flags ACK,URG URG

# Allow ICMP pings
-A OUTPUT -p icmp -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -m state --state ESTABLISHED,RELATED -j ACCEPT

# Allow port 22 for SSH
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT

# Allow port 80 for HTTP
-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT

# Allow port 443 for HTTPS
-A INPUT -m state --state NEW -m tcp -p tcp --dport 443 -j ACCEPT

# Allow ports 25565 - 25575 for Minecraft world servers
-A INPUT -m state --state NEW -m tcp -p tcp --dport 25565:25575 -j ACCEPT

COMMIT


Usage

All commands below assume that you are running them as either the minecraft user or as root (through sudo).

Note: If the script is run as the root user, all important server processes will be started using the minecraft user for security purposes.

su minecraft
/etc/init.d/minecraft_server <option>
or
sudo /etc/init.d/minecraft_server <option>

Options
  • start <world>
    Start the Minecraft world server.  Starts all world servers by default.
  • stop <world>
    Stop the Minecraft world server.  Stops all world servers by default.
  • force-stop <world>
    Forcibly stop the Minecraft world server.  Forcibly stops all world servers by default.
  • restart <world>
    Restart the Minecraft world server.  Restarts all world servers by default.
  • force-restart <world>
    Forcibly restart the Minecraft world server.  Forcibly restarts all world servers by default.
  • status <world>
    Display the status of the Minecraft world server.  Displays the status of all world servers by default.
  • send <world> <command>
    Send a command to a Minecraft world server.
  • logrotate <world>
    Rotate the server.log file.  Rotate the server.log file for all worlds by default.
  • backup <world>
    Backup the Minecraft world.  Backup all worlds by default.
  • screen <world>
    Connect to the Screen holding the world's console.  See more detailed notes below.
  • watch <world>
    Watch the log file for the Minecraft world server.
  • map <world>
    Run the Mincraft Overviewer mapping software on the Minecraft world.  Maps all worlds by default.
  • update <software package>
    Update a software package.  Update the server software and any addons by default.
Available software packages (for update):
  • server - Minecraft server software.
  • client - Minecraft client software, for mapping.
To start all of the world servers, issue the command:
/etc/init.d/minecraft_server start

To start just the world named alpha, issue the command:
/etc/init.d/minecraft_server start alpha

To send a command to a world server, issue the command:
/etc/init.d/minecraft_server send <world> <command>

ie.
/etc/inid.d/minecraft_server send alpha say Hello world!


Screen
The screen option allows an admin to connect to and interact with the Screen holding the Minecraft world server's console.  To exit out of this Screen requires the admin to hit Ctrl-A, followed by the letter d.


Message of the Day (MOTD)
To whisper the message of the day to users as they log into the world, add a file called motd.txt to the /home/minecraft directory.
nano /home/minecraft/motd.txt

Colors
To add colors to your Help or MOTD files, insert the following color codes into your text:
  • §0 - black
  • §1 - blue
  • §2 - deep green
  • §3 - aqua
  • §4 - deep red
  • §5 - purple
  • §6 - gold
  • §7 - gray
  • §8 - dark gray
  • §9 - light blue
  • §a - green
  • §b - teal
  • §c - red
  • §d - magenta
  • §e - yellow
  • §f - white
Example motd.txt:
§fWelcome to Minecraft!
§fToday's theme is §4red§f.
§fLook out for those §2creepers§f!


CraftBukkit
To use the CraftBukkit server distribution instead of the default Mojang server, modify the following lines of code:
## Minecraft server options.

# Choose only one server distribution, leave the other commented out.

# Default Mojang server distribution.
SERVER_URL="http://www.minecraft.net/download/minecraft_server.jar"
SERVER_JAR="minecraft_server.jar"
SERVER_ARGS="nogui"

# CraftBukkit server distribution.
# SERVER_URL="http://ci.bukkit.org/job/dev-CraftBukkit/promotion/latest/Recommended/artifact/target/craftbukkit-0.0.1-SNAPSHOT.jar"
# SERVER_JAR="craftbukkit-0.0.1-SNAPSHOT.jar"
# SERVER_ARGS=""

Bukkit plugins are world specific and are contained within the plugins directory of the world. ie.
/home/minecraft/worlds/alpha/plugins

If you would prefer to use the same plugins directory for all of your worlds, you can create symlinks for each world.  ie.
mkdir /home/minecraft/plugins
ln -s /home/minecraft/plugins /home/minecraft/worlds/alpha/plugins
ln -s /home/minecraft/plugins /home/minecraft/worlds/beta/plugins


Lib Notify
On systems that support lib notify, you can modify the script to print a message on your desktop of important server events.

First, you need to know the name of the display you want to route the messages to.  This is usually ":0.0", but it may be something different on your system.
glxinfo | grep "name of display"

If your username is different than the user used for the Minecraft server, replace $USER_NAME in LIBNOTIFY_USER_NAME=$USER_NAME with the correct username.

Modify the following lines of code in the script.
## Lib-notify configuration

# To use lib-notify to print a message on your desktop of important server events, change the following to a 1.
USE_LIBNOTIFY=0

# The username and display that notifications will be routed to.
LIBNOTIFY_USER_NAME=$USER_NAME
LIBNOTIFY_DISPLAY=":0.0"


License
Consider this code to be in the public domain.  If you have any recommendations or make some useful changes, post a reply in this thread to keep this script evolving.


Issues
I have only tested this code in a Debian/Ubuntu environment, but there is no reason that it shouldn't work in any appropriately configured UNIX-like environment, including Apple Mac OSX and the other BSD variants, with only minor modifications.  If you experience errors running this script, please post a copy of the error message and a note detailing the operating environment where the error occurs, and I'll try to work out a solution with you.

Enjoy,

Sandain

Register or log in to remove.

#2

rad_
    rad_

    Tree Puncher

  • Members
  • 11 posts

Posted 13 January 2011 - 12:28 AM

I had to register to say thank you for this excellent script.  I was really excited to find it and have been really enjoying using it.

I have a few quick bits of feedback:

* The date_time variable is slightly wrong.  You've used a capital M for minutes in the date string where you should have a small m for month:

line 188:
- DATE_TIME=$(date +%Y-%M-%d-%H:%M:%S)
+ DATE_TIME=$(date +%Y-%m-%d-%H:%M:%S)
Obviously this isn't critical, but is an easy enough fix to be worthwhile.

* The map function fails silently if the required folders don't already exist.  The "maps" folder is made, but if the underlying "WORLDNAME" folders aren't already there, nothing happens.  I manually made the folders and it's fine now; not sure if this is a quirk on my system or an oversight....

* Would you consider adding a function to the backup routine that purges existing backups that are x days old, or only keeping the most recent x number of backups?  I know this is a really non-trivial change, but would be super convenient....

Also, I wrote a quick and dirty command that uses Ubuntu's native notification system to alert me when players log in or send messages (my server is just for myself and two RL friends, so it's not overwhelming to plug into all this activity and there's utility in knowing when my friends sign in).  I'd love to be able to incorporate this into your service so it starts (and stops) with the server itself, but I've had no luck at all.  I apologize that this is more of a vanity request, but it's possible someone else might find it useful (and I banged my head against getting it work for entirely too long):

tail -n0 -f $WORLDS_LOCATION/$1/server.log | grep --line-buffered -v "" | while read line; do notify-send "Minecraft Server:" "${line:20}" -i $LOCATION/osd-icon.png; done
You will instantly see how this works because you are a genius, but for anyone (like me) following along at home, I'll explain what happens there:

"tail -f" follows the server log, which gets you easy access to login/logout and all chat console messages
"grep -v """ will filter out lines from the log that you type into the chat console (becomes overwhelming without this and the messages are not important to see in the notification area)
"while read line" simple loop to send the notification for each line as it comes in
"notify-send" is the Ubuntu notification bubbles (see here for details)
"${line:20}" this just trims the line in question of the first 20 characters to remove the timestamps when popping up the notification.  Fancier sed regexps could net you more or less information, but this works well for me.
"osd-icon.png" is whatever you want the icon to be inside the bubble.  I used the 32px one from here and it's an excellent fit.

Curiously, this works when pasted into the terminal directly (with hardcoded values for the paths, natch), but fails when called as a bash script.  Apparently I am full of fail.

I'm sure this isn't useful widely enough to warrant inclusion in your script, but if you could provide some guidance on how to hack it in, I'd be super grateful.... I've tried a number of ways, but each of them broke the service.

Anyway, thanks so much for posting this in the first place.  I'm really surprised there aren't more comments here; you did a great job.

#3

sandain
    sandain

    Zombie Killer

  • Members
  • 184 posts

Posted 13 January 2011 - 02:08 AM

rad_ said:

I had to register to say thank you for this excellent script.  I was really excited to find it and have been really enjoying using it.

I have a few quick bits of feedback:
Nice, I'm really glad that someone else is finding this script useful.  And thank you for the feedback, I really appreciate it.

rad_ said:

* The date_time variable is slightly wrong.  You've used a capital M for minutes in the date string where you should have a small m for month:

line 188:
- DATE_TIME=$(date +%Y-%M-%d-%H:%M:%S)
+ DATE_TIME=$(date +%Y-%m-%d-%H:%M:%S)
Obviously this isn't critical, but is an easy enough fix to be worthwhile.
I noticed this myself yesterday and quietly fixed it. I also added in a %s (seconds since 01/01/1970) in front of the year to make cleaning up old backups easier.  The rest of the filename is purely to make the user's life easier in case they need to restore a backup.

edit: I'm removing the %s, and I'm renaming backup files so that I can easily support incremental backups in addition to full backups in the future.  I figured out a cleaner way to remove old files than trying to calculate how old files are using a difference in seconds from an epoch method.  I'll update the main post here in a few minutes with your suggested change.  I'll work on incremental backups as I have time.  This code is a work in progress, and is mostly untested so for the next few days we'll just have to rely on my interpretation of the man pages being correct (my tests worked, but I only had one backup to play with).  I really need to figure out how to use cron so that I can a) get it to do all the hard work (remembering to do shit) for me, and :P integrate it with the script to make it easy for you guys.



rad_ said:

* The map function fails silently if the required folders don't already exist.  The "maps" folder is made, but if the underlying "WORLDNAME" folders aren't already there, nothing happens.  I manually made the folders and it's fine now; not sure if this is a quirk on my system or an oversight....
Hmm, I'll look into fixing this.  I want this script to build up its environment properly if it isn't already, including building the appropriate directory structure.

edit: You are completely right, total oversight here. Fixed, directories are now created when needed.  The version of c10t that I was originally running wouldn't shut-up when I told it to (-s option), so I had its output routed to /dev/null, explaining the lack of error message when you first ran the map function.  I checked today's version of c10t (the script can now auto update), and it no longer has that problem, so I removed the output routing to allow any errors to flow through.


rad_ said:

* Would you consider adding a function to the backup routine that purges existing backups that are x days old, or only keeping the most recent x number of backups?  I know this is a really non-trivial change, but would be super convenient....

Definitely planned, in fact it is next on my list of features to add in.  I'm also looking at auto-injecting the script into a crontab so that you can schedule backups, but I've never played around with it before so it will be a fun learning experience.

edit: backup files now have a duration until they expire that can be changed in the beginning of the script.  See above.

rad_ said:

Also, I wrote a quick and dirty command that uses Ubuntu's native notification system to alert me when players log in or send messages (my server is just for myself and two RL friends, so it's not overwhelming to plug into all this activity and there's utility in knowing when my friends sign in).  I'd love to be able to incorporate this into your service so it starts (and stops) with the server itself, but I've had no luck at all.  I apologize that this is more of a vanity request, but it's possible someone else might find it useful (and I banged my head against getting it work for entirely too long):

tail -n0 -f $WORLDS_LOCATION/$1/server.log | grep --line-buffered -v "" | while read line; do notify-send "Minecraft Server:" "${line:20}" -i $LOCATION/osd-icon.png; done
You will instantly see how this works because you are a genius, but for anyone (like me) following along at home, I'll explain what happens there:

"tail -f" follows the server log, which gets you easy access to login/logout and all chat console messages
"grep -v """ will filter out lines from the log that you type into the chat console (becomes overwhelming without this and the messages are not important to see in the notification area)
"while read line" simple loop to send the notification for each line as it comes in
"notify-send" is the Ubuntu notification bubbles (see here for details)
"${line:20}" this just trims the line in question of the first 20 characters to remove the timestamps when popping up the notification.  Fancier sed regexps could net you more or less information, but this works well for me.
"osd-icon.png" is whatever you want the icon to be inside the bubble.  I used the 32px one from here and it's an excellent fit.

Curiously, this works when pasted into the terminal directly (with hardcoded values for the paths, natch), but fails when called as a bash script.  Apparently I am full of fail.

I'm sure this isn't useful widely enough to warrant inclusion in your script, but if you could provide some guidance on how to hack it in, I'd be super grateful.... I've tried a number of ways, but each of them broke the service.

This is cool.  I've been thinking of adding in some log parsing.  Being able to tie into libnotify would be a cool option, I'll see what it would take to add it in.

rad_ said:

Anyway, thanks so much for posting this in the first place.  I'm really surprised there aren't more comments here; you did a great job.

Thank you for the feedback!  I'm really happy to see that it is working for other people.

#4

rad_
    rad_

    Tree Puncher

  • Members
  • 11 posts

Posted 14 January 2011 - 04:45 AM

Your recent changes are all really wonderful.  Great work.

I like the new send command, too.  Coupled with the new "list" server command, there's some potentially really useful information to be had here.  From what I can tell, though, the server only outputs the connected players to the log, so log parsing is still needed to really make sense of the info.

I added a quick couple lines to the "status" case in your script since I've got my hacky log notifications anyway, so I can see the results of the list at least.  Doesn't seem to be an elegant way to pull this off for real, though.  You'd have to parse the log completely and have a test case for when no one is connected (the console just returns nothing rather than a message about no one being connected), and then do heavy lifting on the log to output the names into the terminal into a list of their own where the "status" command was likely run.  So close, and yet....

#5

rad_
    rad_

    Tree Puncher

  • Members
  • 11 posts

Posted 14 January 2011 - 10:22 PM

Ran into a new bug today.  I ran "update" through your script, but something failed silently.  Server said it restarted (I think.... If there was an error, it didn't stick out), so I left it alone.  Tried to log in a few hours later and nothing was connecting.

Turns out the server.jar was 0b.  Ran "update" again and it actually pulled the new file and now everything is great again.

Two things, then:

* Update routine should check for http errors and/or make sure the server software isn't 0 bytes.  If an error like that occurs, print a message and don't attempt to restart the server (maybe?).

* Server "start" routine could either have a quick error case for problems with the file itself and then try to update it (like on first run, but for errors like this), or at least print a message.  With my 0 byte server.jar it would just say "starting the server" and then nothing else would happen.  It wasn't too hard to find the problem, so this isn't a big deal, but it occurred to me that calling out the file as the problem would be somewhat helpful (though maybe not worth the extra weight in the code?), and that in doing so, the redownload could actually be cleverly automated....

#6

sandain
    sandain

    Zombie Killer

  • Members
  • 184 posts

Posted 14 January 2011 - 11:43 PM

rad_ said:

Your recent changes are all really wonderful.  Great work.
Thanks!

rad_ said:

I like the new send command, too.  Coupled with the new "list" server command, there's some potentially really useful information to be had here.  From what I can tell, though, the server only outputs the connected players to the log, so log parsing is still needed to really make sense of the info.

I've been looking at the logs, and what I could do to them to make the information more available.  First off, I think I'm going to separate the logs into daily files, then have a cleanup routine similar to backup that will remove old logs.  I also plan on having a separate file in the world directory that will keep track of logged in users, that will be updated by catching the login and logout statements from the server (and if available and wanted, notify the desktop user of these events with libnotify as you requested).  I'm also thinking of tracking user issued server commands, in particular the give command.  I think it might be kind of neat to see a) who is using the command, and :Glass: what they are using it for.

rad_ said:

Ran into a new bug today.  I ran "update" through your script, but something failed silently.  Server said it restarted (I think.... If there was an error, it didn't stick out), so I left it alone.  Tried to log in a few hours later and nothing was connecting.

Turns out the server.jar was 0b.  Ran "update" again and it actually pulled the new file and now everything is great again.

I've put some effort into handling user errors correctly, but I haven't even thought of dealing with other sources of errors, such as you just ran into.  I'll take a closer look at the program and make sure that it catches more of these kind of errors.  Right now the script is deleting the old server.jar before trying to download the new one, I should probably keep it around until after the download finishes in case there is such an error.

If I don't spend too much time playing Minecraft over the weekend, I'll try to get some of the logging stuff coded up.  At the very least I'll take a look at error checking and get a new release out soon.  I've also been reading some rsync tutorials, and it seems like a more logical way to do incremental backups than tar.  I think I'll leave tar in the full backup routine, and set up some kind of rotating rsync for the incremental backups.

edit: The most recent version has some simple error detection on the wget and screen commands, if they fail it will now print an error message.  When updating the server it will restore a backup if available then stop execution, when updating c10t it will just print its message then stop execution.  If this method fails to detect the 0kb file issue that you saw, I might be able to add in some form of md5sum checking of the server jar or something (does Notch post this info??).

#7

deMangler

Posted 15 January 2011 - 02:35 PM

sandain said:

Download
Save the file as "minecraft_server", without the quotes.

Pastebin: http://pastebin.com/Bs4fxg77


Last Update

Excellent - Thank yoe very much for sharing this.


dM

#8

CFCParadox
  • Location: Mississauga, Canada
  • Minecraft: ProvisionHost

Posted 15 January 2011 - 03:57 PM

Interesting script I may try this our later and good luck with this project!

Posted Image


#9

rad_
    rad_

    Tree Puncher

  • Members
  • 11 posts

Posted 15 January 2011 - 10:15 PM

I don't know why I didn't think of this sooner:
## Line 387
	  # Show the status of each world requested.
	  for WORLD in $WORLDS; do
		 printf "  $WORLD > status: "
		 if [ $(serverRunning $WORLD) = 1 ]; then
			printf "running.\n"
			sendCommand $WORLD "list"
			printf "  $WORLD > connected players: "
			PLAYERLIST=`eval tail -n1 $WORLDS_LOCATION/$WORLD/server.log | grep --line-buffered "players:"`
			if [ ${#PLAYERLIST} == "46" ]; then
			  printf "none\n"
			else
			  printf "${PLAYERLIST:46}\n"
			fi
		 else
			printf "not running.\n"
		 fi
	  done
Instead of writing the log in/out states to a file, you can just send the list command and immediately tail the log for the connected players.  (This will report "none" if something else is concurrently logged and the last line isn't the connected players list.  Not sure how likely this is.  Tried implementing a check for zero length on $PLAYERLIST and running the list/tail again if it was, but didn't want to structure that into a loop, so just pulled the check out....)

One benefit from doing it the way you wanted (current list of logged in players in a separate file), though, is that having that info handy would make listening for chats in the log easier (grep "<$1>|<$2>|..." -> though I'm not sure how best to structure that code on account of ther ebeing a variable number of usernames)....  But it sounds a lot more complicated.

The above works great on my end, but I had to change your script to execute as BASH instead of just SH in line 1.  Apparently SH doesn't support the substring syntax and I couldn't find a reference anywhere for relevant operations.  No noticeable impact elsewhere for the change, but I'm a little wary.  Did you use SH for any explicit reasons?

Also, this means I can probably put the libnotify stuff from before in the script proper (inelegant though it is), since the trim function was the likely cause of the errors there, too.  Will have to roll up my sleeves and more properly parse the log to keep notifications down....

As ever: thank you and you rock.

#10

rad_
    rad_

    Tree Puncher

  • Members
  • 11 posts

Posted 15 January 2011 - 10:38 PM

Strike that about the chats.  Potentially better idea:

1. Parse log for "<*>" lines, strip timestamp, write to chat.log file as they come in
2. Follow chat.log and grep -v yourself (hardcoded variable in script? read from admin file?)
3. libnotify the lines that are left

No need to follow log in/out, and seems like much simpler logic to structure.  What do you think?

#11

deMangler

Posted 16 January 2011 - 01:28 AM

For some reason I couldn't get the script from pastebin without having ^M's at the end of each line. So the script would not run. Maybe I don't understand pastebin.

So, just in case anyone else is having this problem, running (for example if you call your download file pesky-ctrl-m-bah ):

sed 's/'"$(printf '\015')"'$//g' pesky-ctrl-m-bah >>minecraft_server

produces the file minecraft_server with no pesky ^M's

dM

#12

sandain
    sandain

    Zombie Killer

  • Members
  • 184 posts

Posted 16 January 2011 - 06:56 AM

deMangler said:

For some reason I couldn't get the script from pastebin without having ^M's at the end of each line. So the script would not run. Maybe I don't understand pastebin.

So, just in case anyone else is having this problem, running (for example if you call your download file pesky-ctrl-m-bah ):

sed 's/'"$(printf '\015')"'$//g' pesky-ctrl-m-bah >>minecraft_server

produces the file minecraft_server with no pesky ^M's

dM


I've never had a problem with ^M getting inserted into things with Pastebin, but I've been thinking of changing hosts anyway.  I would like to include in the update routine a method to update the script, but the address for Pastebin changes with every update.  Does Sourceforge sound reasonable?  I'm using it for a couple of other projects, it might work here too.

BTW: Pastebin has a download link on the upper right hand side of the page.  I'm not sure if that is what is giving you the problem or not, but it seems to work for me.

#13

sandain
    sandain

    Zombie Killer

  • Members
  • 184 posts

Posted 16 January 2011 - 07:21 AM

rad_ said:

Apparently SH doesn't support the substring syntax and I couldn't find a reference anywhere for relevant operations.  No noticeable impact elsewhere for the change, but I'm a little wary.  Did you use SH for any explicit reasons?

SH is just a soft link to your default shell environment.  User shells are often Bash by default, but on Debian and Ubuntu based distros, they are switching over to using Dash as the default shell for root.  Since I want this script to be as portable as possible, I've used only the subset of the shell language that is supported by almost all shell environments, and Dash is as limited as they come.  You can do pretty much anything you want to do in Dash without resorting to using a Bash specific extension with very little effort as I've so far found.  Feel free to change the shabang line to Bash if you want, it will make little difference.

rad_ said:

Strike that about the chats.  Potentially better idea:

1. Parse log for "<*>" lines, strip timestamp, write to chat.log file as they come in
2. Follow chat.log and grep -v yourself (hardcoded variable in script? read from admin file?)
3. libnotify the lines that are left

No need to follow log in/out, and seems like much simpler logic to structure.  What do you think?

I'm still working on the code, but I should be able to track users logging in and out by searching for the following patterns:
Logins:
 

I also plan on capturing any command response data issued by the send command, and returning the text to the console that issued the command.  This might be tricky, but if I can get it to work, I'll be looking for the following pattern:
 

I'm still quite a ways off from having anything usable, I'll try to get something posted this weekend.  I've been working on my minecart station quite a bit lately, and in fact hit a major milestone with it today:  the minecart request button finally works.  Four holding bays, two levels of tracks, and two levels of logic circuits... I never thought I would ever use my logic circuit classes in college, but they are surprisingly coming in handy at playing this game. Ha.  Programming in a high level language like Perl, Java, or even shell script is light-years easier than dealing with 1's, 0's, and some NOR gates.  Debugging this stuff is hell!  I've gained some new respect for the world's Electrical Engineers, seriously.

#14

rad_
    rad_

    Tree Puncher

  • Members
  • 11 posts

Posted 16 January 2011 - 08:40 AM

sandain said:

You can do pretty much anything you want to do in Dash without resorting to using a Bash specific extension with very little effort as I've so far found.
According to this, the replacement for my simple Bash substring operation is to use sed or awk, which I couldn't make work for the life of me the first time around.  I will bow out and just wait to see what you come up with....

Congrats on the minecart station!

#15

kroimon
    kroimon

    Out of the Water

  • Members
  • 3 posts

Posted 16 January 2011 - 04:22 PM

Great script, thank you!

The only problem I have is that the c10t function only works for worlds called "world", as this is hardcoded:
su -c "$C10T_BIN -s -w $WORLDS_LOCATION/$1/world -o $MAPS_LOCATION/$1/surface.png" $USER_NAME
For a world called "beta" for example, the world files actually are in $WORLDS_LOCATION/beta/beta, not $WORLDS_LOCATION/beta/world. Therefore the lines should be as follows:
su -c "$C10T_BIN -s -w $WORLDS_LOCATION/$1/$1 -o $MAPS_LOCATION/$1/surface.png" $USER_NAME

An updated version can be found here.

#16

sandain
    sandain

    Zombie Killer

  • Members
  • 184 posts

Posted 17 January 2011 - 01:30 AM

kroimon said:

Great script, thank you!

The only problem I have is that the c10t function only works for worlds called "world", as this is hardcoded:
su -c "$C10T_BIN -s -w $WORLDS_LOCATION/$1/world -o $MAPS_LOCATION/$1/surface.png" $USER_NAME
For a world called "beta" for example, the world files actually are in $WORLDS_LOCATION/beta/beta, not $WORLDS_LOCATION/beta/world. Therefore the lines should be as follows:
su -c "$C10T_BIN -s -w $WORLDS_LOCATION/$1/$1 -o $MAPS_LOCATION/$1/surface.png" $USER_NAME

An updated version can be found here.

I've thought of changing the code so that Minecraft and the script are using the same name for the world (right now Minecraft only sees the world name 'world' regardless of what the script thinks the world name is), but the change needs to happen in a few places.  For instance, when first starting the server, it checks to make sure that the server.properties file exists, and it defaults to using a world name of 'world' if it doesn't.  As far as I know, the only reason you should actually hit an issue here is if you started using this script with a previously running server, and in that case you would have to modify your config anyway.  At this point, I'm a bit loathe to change it, but it is a probably a good idea in the long run.  The problem is, this script has an existing user-base, so I'll either have to add code to update the old way to the new way of doing things, or break old configurations.  Neither option is ideal, hence my reluctance to do this right now.  =/

Edit:  I went ahead and made this change.  The script should hopefully update any old configurations.

#17

thedrock
    thedrock

    Out of the Water

  • Members
  • 5 posts

Posted 18 January 2011 - 01:51 AM

Hi,

Thanks for the great script. I have it running (mainly).. but I had a few issues.

My system: Ubuntu 9.10. I had the other script running with dated backups as a bash script if that makes a difference.

1. wont' download new c10t bin. (can't find an error)
But I just placed the bin in the correct dir

2. Backup places a oddly named .gz file into the correct dir. I take it that my system doesn't like the date code you use.

Also it looks like i have my working dirs a bit different. I tried to edit it but maybe there is something missing.  (ie. It seems to me that your worlds are in /minecraft_server/worlds/world/world

Any suggestions would be greatly appreciated.
Cheers,
d

#18

sandain
    sandain

    Zombie Killer

  • Members
  • 184 posts

Posted 18 January 2011 - 10:10 PM

thedrock said:

Hi,

Thanks for the great script. I have it running (mainly).. but I had a few issues.

My system: Ubuntu 9.10. I had the other script running with dated backups as a bash script if that makes a difference.

1. wont' download new c10t bin. (can't find an error)
But I just placed the bin in the correct dir

2. Backup places a oddly named .gz file into the correct dir. I take it that my system doesn't like the date code you use.

Also it looks like i have my working dirs a bit different. I tried to edit it but maybe there is something missing.  (ie. It seems to me that your worlds are in /minecraft_server/worlds/world/world

Any suggestions would be greatly appreciated.
Cheers,
d

Try the most recent version of the script and let me know if you are still having the same problems.  I've made a few changes that might clean things up for you.

If you are still having issues, let me know what the output from the following commands are:
uname -m
date +%Y-%m-%d-%H:%M:%S

The current code tells Minecraft to load the world files located in /home/minecraft/worlds/alpha/alpha if the world's name is 'alpha'.  The first alpha denotes the world name that the script sees, the second is actually the level-name in the server.properties file.  Old versions of the script told Minecraft that the level-name was 'world', regardless of what the script thought the world name was (ie /home/minecraft/worlds/alpha/world), but I found this slightly confusing myself and was not surprised to see issues in this thread.  I just changed it so that the world name that the script sees is the same as the level-name that Minecraft sees.  The double alpha in the directory name is still required to keep the Minecraft server files for each world separate from one another easily (and keep the server itself happy).  I hope this explains your last question.

#19

thedrock
    thedrock

    Out of the Water

  • Members
  • 5 posts

Posted 19 January 2011 - 04:32 AM

Hey,

Thanks for replying. It didn't make a difference.  I am not sure what I am doing wrong here. The only change I have made is the folders. I found that kept everything in a slightly different structure. (If you think that is an issue I can explain it)

uname -m
i686
date +%Y-%m-%d-%H:%M:%S
2011-01-18-20:30:39

Anything else I can try? I guess there will be a web interface for this sort of thing soon. (bukket? or something). But I like the ability to SSH in and make these simple changes...

Thanks again,
d

#20

sandain
    sandain

    Zombie Killer

  • Members
  • 184 posts

Posted 19 January 2011 - 05:12 AM

thedrock said:

Hey,

Thanks for replying. It didn't make a difference.  I am not sure what I am doing wrong here. The only change I have made is the folders. I found that kept everything in a slightly different structure. (If you think that is an issue I can explain it)

uname -m
i686
date +%Y-%m-%d-%H:%M:%S
2011-01-18-20:30:39

Anything else I can try? I guess there will be a web interface for this sort of thing soon. (bukket? or something). But I like the ability to SSH in and make these simple changes...

Thanks again,
d

Ok, that explains the issue with updating c10t.  My box returns 'x86_64' with the uname command, and I assumed that 32 bit boxes returned 'x86'.  I'll make some changes to fix this one.

As far as the issue with the backups, give me a directory listing or an example of the failed backup names.  It should look like 'fullBackup-alpha-2011-01-12-21:41:55.tar.gz'.  Your date command appears to function the same as mine, so I'm not sure what's going on here.  Maybe I should simplify the names by removing the time stamp, although I like being able to have multiple backups in a single day.  I'll try to think of a possible work around while I wait for your reply on this one.