Skip to content

Instantly share code, notes, and snippets.

@cking
Created February 10, 2025 14:58
Show Gist options
  • Save cking/2736008f719ad96f6593b61b2ab81688 to your computer and use it in GitHub Desktop.
Save cking/2736008f719ad96f6593b61b2ab81688 to your computer and use it in GitHub Desktop.
My minecraft

Needs:

  • rdiff-backup
  • tmux
  • zstd
  • tar
  • awk
  • ps
  • grep
  • cut

And obiously java

#!/bin/bash
# set default settings
MCPATH=$(realpath $(dirname "$BASH_SOURCE[0]"))
SERVICE=$(basename $MCPATH)
BACKUPPATH="$MCPATH/backup"
JAVA_OPTIONS="@user_jvm_args.txt"
PORT=$(grep server-port $MCPATH/server.properties | cut -d '=' -f 2)
JAVA=$(which java)
JAR="-Dlog4j2.formatMsgNoLookups=true @libraries/net/minecraftforge/forge/1.19.2-43.2.8/unix_args.txt"
INVOCATION="${JAVA} ${JAVA_OPTIONS} ${JAR} nogui"
# load user settings
if [ -f mc-config.sh ]; then
source mc-config.sh
fi
if [ -z "$PORT" ]; then
PORT=25565
fi
# Settings end
is_running() {
if [ ! -e $MCPATH/java.pid ]; then
return 1
fi
pid=$(cat $MCPATH/java.pid)
if [ -z $pid ]; then
return 1
fi
ps -eo "%p" | grep "^\\s*$pid\\s*\$" > /dev/null
return $?
}
mc_start() {
if is_running; then
echo "Tried to start but $SERVICE was already running!"
return
fi
echo -n "$SERVICE starting."
cd $MCPATH
tmux new-session -d -s "mc$PORT" -n "mc$PORT" "$INVOCATION"
for (( i=0; i < 10; i++ )); do
tmuxpid=$(tmux list-sessions -F "#{session_name} #{pid}" | awk -v port="mc$PORT" '$1 == port {print $2}')
javapid=$(ps -eo '%P %p' | grep "^\\s*$tmuxpid " | awk -v tpid="$tmuxpid" '$1 == tpid {print $2}')
if [[ -n "$tmuxpid" && -n "$javapid" ]]; then
break
fi
echo -n .
sleep 1
done
echo
if [[ -n "$tmuxpid" && -n "$javapid" ]]; then
echo "$SERVICE is now running."
echo "$javapid" > $MCPATH/java.pid
else
echo "Could not start $SERVICE."
fi
}
mc_stop() {
if ! is_running; then
echo "$SERVICE was not running."
return
fi
echo "$SERVICE saving map..."
mc_exec "say SERVER SHUTTING DOWN IN 10 SECONDS. Saving map..."
mc_exec "save-all"
sleep 10
echo -n "$SERVICE stopping."
mc_exec "stop"
for (( i=0; i < 20; i++ )); do
is_running || break
echo -n .
sleep 1
done
echo
if is_running; then
echo "$SERVICE could not be shut down cleanly... still running."
mc_kill
else
echo "$SERVICE is shut down."
fi
rm $MCPATH/java.pid
}
mc_saveoff() {
if is_running; then
echo "$SERVICE is running... suspending saves"
mc_exec "say SERVER BACKUP STARTING. Server going readonly..."
mc_exec "save-off"
mc_exec "save-all"
sync
sleep 10
else
echo "$SERVICE was not running. Not suspending saves."
fi
}
mc_saveon() {
if is_running; then
echo "$SERVICE is running... re-enabling saves"
mc_exec "save-on"
mc_exec "say SERVER BACKUP ENDED. Server going read-write..."
else
echo "$SERVICE was not running. Not resuming saves."
fi
}
mc_kill() {
pid=$(cat $MCPATH/java.pid)
echo "terminating process with pid $pid"
kill $pid
for (( i=0; i < 10; i++ )); do
is_running || break
sleep 1
done
if is_running; then
echo "$SERVICE could not be terminated, killing..."
kill -SIGKILL $pid
echo "$SERVICE killed"
else
echo "$SERVICE terminated"
fi
}
mc_backup() {
echo "Backing up minecraft world"
[ -d "$BACKUPPATH/world" ] || mkdir -p "$BACKUPPATH/world"
echo "*_old\m**/*_old" | \
rdiff-backup backup --exclude-globbing-filelist-stdin $MCPATH "$BACKUPPATH/world"
echo "Backup complete"
}
mc_archive() {
if (($(date +%H) == 0)) && (($(date +%M) < 15)); then
echo "Compressing world..."
folder=$BACKUPPATH/world
archive=$BACKUPPATH/$(date +%Y-%m-%d).tar.zstd
tar --zstd -cf "$archive"--exclude="rdiff-backup-data" -C "$folder" .
echo "Deleting old archives"
find $BACKUPPATH -maxdepth 1 -type f -mtime +7 -delete
fi
}
mc_exec() {
if is_running; then
tmux send-keys -t "mc$PORT" "$@" C-m
else
echo "$SERVICE was not running. Not executing command."
fi
}
case "$1" in
start)
mc_start
;;
stop)
mc_stop
;;
restart)
mc_stop
mc_start
;;
backup)
mc_saveoff
mc_backup
mc_saveon
mc_archive
;;
exec)
shift
mc_exec "$@"
;;
status)
if is_running; then
echo "$SERVICE is running."
else
echo "$SERVICE is not running."
exit 1
fi
;;
*)
echo "Usage: $(readlink -f $0) {start|stop|restart|backup|exec|status}"
exit 1
;;
esac
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment