#!/bin/bash
# /etc/init.d/minecraft
# version 0.3.2 2011-01-27 (YYYY-MM-DD)

### BEGIN INIT INFO
# Provides:   minecraft
# Required-Start: $local_fs $remote_fs
# Required-Stop:  $local_fs $remote_fs
# Should-Start:   $network
# Should-Stop:    $network
# Default-Start:  2 3 4 5
# Default-Stop:   0 1 6
# Short-Description:    Minecraft server
# Description:    Starts the minecraft server
### END INIT INFO

#Settings
SERVICE='minecraft_server.jar'
USERNAME="minecraft"
MCPATH='/home/minecraft'
CPU_COUNT=1
#INVOCATION="java -Xmx1024M -Xms1024M -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalPacing -XX:ParallelGCThreads=$CPU_COUNT -XX:+AggressiveOpts -jar minecraft_server.jar nogui"
INVOCATION="java -Xmx800M -Xms800M -XX:+UseSerialGC -jar minecraft_server.jar nogui"
BACKUPPATH='/home/backup-minecraft'
ONDISKPATH='/home/minecraft-ondisk'

. /lib/init/vars.sh

. /lib/lsb/init-functions


ME=`whoami`
as_user() {
  if [ $ME == $USERNAME ] ; then
    bash -c "$1"
  else
    su - $USERNAME -c "$1"
  fi
}

mc_start() {
  if ps ax | grep -v grep | grep -v -i SCREEN | grep $SERVICE > /dev/null
  then
    log_progress_msg "Tried to start but $SERVICE was already running!"
    return 0
  else
    #echo "$SERVICE was not running... starting."
    log_progress_msg "Loading world into RAMdisk"
    as_user "cp -Rfu --preserve $ONDISKPATH/* $MCPATH/"
    log_progress_msg "Spawing process into virtual terminal"
    as_user "cd $MCPATH && screen -dmS minecraft $INVOCATION"
    sleep 7
    if ps ax | grep -v grep | grep -v -i SCREEN | grep $SERVICE > /dev/null
    then
      #echo "$SERVICE is now running."
      return 1
    else
      #echo "Could not start $SERVICE."
      return 2
    fi
  fi
}

mc_saveoff() {
        if ps ax | grep -v grep | grep -v -i SCREEN | grep $SERVICE > /dev/null
	then
		echo "$SERVICE is running... suspending saves"
		as_user "screen -p 0 -S minecraft -X eval 'stuff \"say SERVER BACKUP STARTING. Server going readonly...\"\015'"
                sleep 1
                as_user "screen -p 0 -S minecraft -X eval 'stuff \"save-off\"\015'"
                sleep 1
                as_user "screen -p 0 -S minecraft -X eval 'stuff \"save-all\"\015'"
                sync
		sleep 10
	else
                echo "$SERVICE was not running. Not suspending saves."
	fi
}

mc_saveon() {
        if ps ax | grep -v grep | grep -v -i SCREEN | grep $SERVICE > /dev/null
	then
		echo "$SERVICE is running... re-enabling saves"
                as_user "screen -p 0 -S minecraft -X eval 'stuff \"save-on\"\015'"
                sleep 1 
                as_user "screen -p 0 -S minecraft -X eval 'stuff \"say SERVER BACKUP ENDED. Server going read-write...\"\015'"
                sleep 1
	else
                echo "$SERVICE was not running. Not resuming saves."
	fi
}

mc_stop() {
        if ps ax | grep -v grep | grep -v -i SCREEN | grep $SERVICE > /dev/null
        then
                #echo "$SERVICE is running... stopping."
		log_progress_msg "Updating world RAM data"
                as_user "screen -p 0 -S minecraft -X eval 'stuff \"say SERVER SHUTTING DOWN IN 10 SECONDS. Saving map...\"\015'"
                sleep 1
                as_user "screen -p 0 -S minecraft -X eval 'stuff \"save-all\"\015'"
                sleep 10
                as_user "screen -p 0 -S minecraft -X eval 'stuff \"stop\"\015'"
                sleep 7
    		log_progress_msg "Saving world into disk"
		as_user "cp -Rfu --preserve $MCPATH/* $ONDISKPATH/"
#        else
#                echo "$SERVICE was not running."
        fi
        if ps ax | grep -v grep | grep -v -i SCREEN | grep $SERVICE > /dev/null
        then
                echo "$SERVICE could not be shut down... still running."
                return 1
        else
                echo "$SERVICE is shut down."
                return 0
        fi
}


mc_update() {
  if ps ax | grep -v grep | grep -v -i SCREEN | grep $SERVICE > /dev/null
  then
    echo "$SERVICE is running! Will not start update."
  else
    MC_SERVER_URL=http://www.minecraft.net/download/minecraft_server.jar?v=`date | sed "s/[^a-zA-Z0-9]/_/g"`
    as_user "cd $MCPATH && wget -q -O $MCPATH/minecraft_server.jar.update $MC_SERVER_URL"
    if [ -f $MCPATH/minecraft_server.jar.update ]
    then
      if `diff $MCPATH/minecraft_server.jar $MCPATH/minecraft_server.jar.update >/dev/null`
        then 
          echo "You are already running the latest version of $SERVICE."
        else
          as_user "mv $MCPATH/minecraft_server.jar.update $MCPATH/minecraft_server.jar"
          echo "Minecraft successfully updated."
      fi
    else
      echo "Minecraft update could not be downloaded."
    fi
  fi
}

mc_backup() {
   echo "Backing up minecraft world"

   if [ ! -d $BACKUPPATH/today ]
   then
     as_user "mkdir $BACKUPPATH/today"
   fi

   if [ ! -d $BACKUPPATH/yesterday ]
   then
     as_user "mkdir $BACKUPPATH/yesterday"
   fi

   if [ ! -d $BACKUPPATH/beforeyesterday ]
   then
     as_user "mkdir $BACKUPPATH/beforeyesterday"
   fi

   if [ ! -e $BACKUPPATH/today/`date "+%Y.%m.%d"` ]
   then
     as_user "rm -rf $BACKUPPATH/beforeyesterday/*"
     as_user "cp -r $BACKUPPATH/yesterday/* $BACKUPPATH/beforeyesterday/"
     as_user "rm -rf $BACKUPPATH/yesterday/*"
     as_user "cp -r $BACKUPPATH/today/* $BACKUPPATH/yesterday/"
     as_user "rm -rf $BACKUPPATH/today/*"
     as_user "touch $BACKUPPATH/today/`date "+%Y.%m.%d"`"
     echo "Rotated today to yesterday and yesterday to beforeyesterday"
   fi

   as_user "tar cf $BACKUPPATH/today/`date "+%Y.%m.%d.%H.%M"`.tar $MCPATH/world"
   as_user "cp -Rfu --preserve $MCPATH/* $ONDISKPATH/"
   echo "Backup completed"
}

mc_weekly_backup() {
   echo "Backing up weekly minecraft world"

   if [ ! -d $BACKUPPATH/weekly ]
   then
     as_user "mkdir $BACKUPPATH/weekly"
   fi

   as_user "tar czf $BACKUPPATH/weekly/`date "+%Y.%V.%b.%d.%H.%M"`.tgz $MCPATH/world"
   echo "Weekly backup completed"
}

mc_say() {
   as_user "screen -p 0 -S minecraft -X eval 'stuff \"say $1\"\015'"
}

mc_help() {
   as_user "screen -p 0 -S minecraft -X eval 'stuff \"help\"\015'"
   sleep 1
   as_user "tail -n 30 $MCPATH/server.log"
}

mc_cmd() {
   as_user "screen -p 0 -S minecraft -X eval 'stuff \"$1\"\015'"
}

mc_log() {
   if [ "$1" ]
   then
     as_user "tail -n $1 $MCPATH/server.log"
   else
     as_user "tail $MCPATH/server.log"
   fi
}

#Start-Stop here
case "$1" in
  start)
    log_daemon_msg "Starting Minecraft server"
    mc_start
    case "$?" in
            0|1)
               log_end_msg 0 ;;
            2)
               log_end_msg 1 ;;
    esac
    ;;
  stop)
    log_daemon_msg "Stopping Minecraft server"
    mc_stop
    case "$?" in
            0)
               log_end_msg 0 ;;
            1)
               log_end_msg 1 ;;
    esac
    ;;
  restart)
    log_daemon_msg "Restarting Minecraft"
    mc_stop
    case "$?" in
            0)
    	       mc_start
               case "$?" in
                         0) log_end_msg 1 ;; #Old process running
                         1) log_end_msg 0 ;;
                         *) log_end_msg 1 ;;
               esac
               ;;
            *)
               log_end_msg 1
            ;;
    esac
    ;;
  update)
    mc_stop
    mc_backup
    mc_update
    mc_start
    ;;
  backup)

    # Check if server running
    if ps ax | grep -v grep | grep -v -i SCREEN | grep $SERVICE > /dev/null
    then
      # Check if someone is playing
      # Update players log
      mc_cmd "list"
      # Wait for log written
      sleep 1
      # Take the last string, hoping to have the list command message (with the players)
      players_string=`tail -n1 /home/minecraft/server.log`
      # Will hope the string 'players:' will be here (5th column)
      verify_line_players=`echo $players_string | cut -f5 -d\ `
      if [ $verify_line_players == "players:" ]
      then
         # Verify the number of players
         # The string is 5 words length, so the rest are players
         num_players=$(( `tail -n1 /home/minecraft/server.log | wc -w ` ))
         if [ $num_players -ge 6 ]
         then
           # There are players, must backup
           as_user "touch $BACKUPPATH/users_playing"
           mc_saveoff
           mc_backup
           mc_saveon
         else
           # There are not players, but maybe were, so must backup anyway
           if [ -f $BACKUPPATH/users_playing ]
           then
             as_user "rm $BACKUPPATH/users_playing"
             mc_saveoff
             mc_backup
             mc_saveon
             #mc_stop
             #sleep 10
             #mc_start
	   fi
         fi
      else
         # Couldn't get the number of players, so someone is playing (chatting)
         # Will have to make the backup
         as_user "touch $BACKUPPATH/users_playing"
         mc_saveoff
         mc_backup
         mc_saveon
      fi
    fi
    ;;
  weekly_backup)
    mc_saveoff
    mc_weekly_backup
    mc_saveon
    ;;
  say)
    mc_say "$2"
    ;;
  help)
    mc_help
    ;;
  cmd)
    mc_cmd "$2"
    ;;
  log)
    mc_log "$2"
    ;;
  saveon)
    mc_saveon
    ;;
  status)
    if ps ax | grep -v grep | grep -v -i SCREEN | grep $SERVICE > /dev/null
    then
      log_action_msg "$SERVICE is running."
      return 0
    else
      log_action_msg "$SERVICE is not running."
      exit 3
    fi
    ;;

  *)
  echo "Usage: /etc/init.d/minecraft {start|stop|update|backup|weekly_backup|status|restart|say|help|cmd|log}"
  echo "    backup  - will make a backup of the world if the server is running and are players playing"
  echo "    weekly_backup - will make a backup (always)"
  echo "    say 'message' - write a message to all server"
  echo "    help - shows commands"
  echo "    cmd 'command params' - execute command"
  echo "    log (default 10)  - show 10 lines of log"
  echo "    log numlines - show the desired number of lines of log"
  exit 3
  ;;
esac

exit 0

