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 |