241 lines
9 KiB
Bash
241 lines
9 KiB
Bash
#!/bin/bash
|
|
# ClayGarth.com - Sequential Factorio server manager using INI config
|
|
# Fancy terminal output version
|
|
|
|
CONFIG_FILE="/home/factorio/servers-config.ini"
|
|
|
|
# Color and style codes
|
|
RED='\033[1;31m'
|
|
GREEN='\033[1;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[1;34m'
|
|
CYAN='\033[1;36m'
|
|
BOLD='\033[1m'
|
|
UNDERLINE='\033[4m'
|
|
RESET='\033[0m'
|
|
|
|
timestamp() {
|
|
date +"%Y-%m-%d %H:%M:%S"
|
|
}
|
|
|
|
section() {
|
|
echo -e "${BOLD}${CYAN}\n=============================="
|
|
echo -e "$1"
|
|
echo -e "==============================${RESET}"
|
|
}
|
|
|
|
status() {
|
|
# $1 = message, $2 = color
|
|
echo -e "${2}${BOLD}[$(timestamp)]${RESET} $1"
|
|
}
|
|
|
|
# Monitor a server's log for "Opening socket for broadcast" and show a ready message
|
|
monitor_server_ready() {
|
|
local server="$1"
|
|
local log_file="/home/factorio/servers/${server}/factorio-current.log"
|
|
local status_file="/tmp/factorio_server_ready_${server}"
|
|
rm -f "$status_file"
|
|
if timeout 120 grep -m 1 "Opening socket for broadcast" <(tail -n 0 -F "$log_file") > /dev/null; then
|
|
touch "$status_file"
|
|
fi
|
|
}
|
|
|
|
# Stop a single server, monitor for clean shutdown, and cleanup
|
|
stop_server() {
|
|
local server="$1"
|
|
local log_file="/home/factorio/servers/${server}/factorio-current.log"
|
|
local monitor_string="Goodbye"
|
|
|
|
section "🛑 Stopping ${server} server"
|
|
screen -p 0 -S "$server" -X stuff $'/quit\n' >> /dev/null 2>&1
|
|
|
|
status "Monitoring $server log for shutdown confirmation: $log_file" "$YELLOW"
|
|
if [ -f "$log_file" ] && grep -q "$monitor_string" "$log_file"; then
|
|
status "$server was already stopped." "$GREEN"
|
|
else
|
|
if [ -f "$log_file" ] && timeout 30 tail -n 0 -F "$log_file" | grep -q "$monitor_string"; then
|
|
status "$server has saved and stopped cleanly." "$GREEN"
|
|
else
|
|
status "Timeout: $server did not shut down cleanly in 30 seconds." "$RED"
|
|
screen -S "$server" -p 0 -X stuff "^C" >> /dev/null 2>&1
|
|
sleep 2
|
|
screen -X -S "$server" quit >> /dev/null 2>&1
|
|
sleep 1
|
|
fi
|
|
fi
|
|
|
|
# Cleanup
|
|
status "Cleaning up $server server files..." "$BLUE"
|
|
cd "/home/factorio/servers/$server/saves" 2>/dev/null && rm ./*.tmp.zip >> /dev/null 2>&1
|
|
cd "/home/factorio/servers/$server/" 2>/dev/null && rm -f .lock >> /dev/null 2>&1
|
|
cp /home/factorio/mods/mod-settings.dat /home/factorio/mods/default/ > /dev/null 2>&1
|
|
cp /home/factorio/mods/mod-list.json /home/factorio/mods/default/ > /dev/null 2>&1
|
|
status "Cleanup completed for $server." "$GREEN"
|
|
}
|
|
|
|
# Start a single server with its config
|
|
start_server() {
|
|
local server="$1"
|
|
local port="$2"
|
|
local settings="$3"
|
|
local config="$4"
|
|
local mod_directory="$5"
|
|
local use_whitelist="$6"
|
|
|
|
local factorio_executable="/home/factorio/factorio/bin/x64/factorio"
|
|
if [ ! -x "$factorio_executable" ]; then
|
|
status "Error: Factorio executable not found or not executable at $factorio_executable" "$RED"
|
|
exit 1
|
|
fi
|
|
|
|
local start_command="$factorio_executable --start-server-load-latest --server-settings $settings --config $config --executable-path /home/factorio/factorio/bin/x64/ --mod-directory $mod_directory --port $port"
|
|
if [ "$use_whitelist" = "true" ]; then
|
|
start_command="$start_command --use-server-whitelist true"
|
|
fi
|
|
|
|
section "🚀 Starting ${server} server"
|
|
status "Command: $start_command" "$CYAN"
|
|
/usr/bin/screen -dmS "$server" $start_command
|
|
sleep 2
|
|
if screen -list | grep -q "\.${server}[[:space:]]"; then
|
|
status "$server started successfully." "$GREEN"
|
|
# Start log monitor in the background
|
|
monitor_server_ready "$server" &
|
|
else
|
|
status "Error: Failed to start $server." "$RED"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Update Factorio and mods
|
|
update_factorio() {
|
|
section "⬆️ Updating Factorio and Mods"
|
|
local FACTORIO_API="https://factorio.com/api/latest-releases"
|
|
local FACTORIO_RESPONSE FACTORIO_VERSION FACTORIO_VERSION_NO_PERIODS VERSION_FILE CURRENT_VERSION
|
|
|
|
FACTORIO_RESPONSE=$(curl -s "$FACTORIO_API")
|
|
FACTORIO_VERSION=$(echo "$FACTORIO_RESPONSE" | jq -r '.stable.headless')
|
|
FACTORIO_VERSION_NO_PERIODS=$(echo "$FACTORIO_VERSION" | tr -d '.')
|
|
VERSION_FILE="/home/factorio/factorio_version.txt"
|
|
|
|
if [ -f "$VERSION_FILE" ]; then
|
|
CURRENT_VERSION=$(cat "$VERSION_FILE")
|
|
if [ "$FACTORIO_VERSION_NO_PERIODS" -gt "$CURRENT_VERSION" ]; then
|
|
status "New Factorio version available. Updating..." "$YELLOW"
|
|
echo "$FACTORIO_VERSION_NO_PERIODS" > "$VERSION_FILE"
|
|
cd /home/factorio || exit 1
|
|
wget https://www.factorio.com/get-download/stable/headless/linux64 -O factorio.tar.xz
|
|
tar -xf factorio.tar.xz
|
|
chmod +x /home/factorio/factorio/bin/x64/factorio > /dev/null 2>&1
|
|
rm -f factorio.tar.xz
|
|
status "Factorio updated to $FACTORIO_VERSION." "$GREEN"
|
|
else
|
|
status "Factorio is already up-to-date." "$GREEN"
|
|
fi
|
|
else
|
|
echo "$FACTORIO_VERSION_NO_PERIODS" > "$VERSION_FILE"
|
|
status "Factorio version file created." "$GREEN"
|
|
fi
|
|
|
|
#status "Updating mods..." "$BLUE"
|
|
cp /home/factorio/mods/mod-list.json /home/factorio/mods/default/ > /dev/null 2>&1
|
|
#status "Mods updated." "$GREEN"
|
|
}
|
|
|
|
# Sequentially stop and/or start servers as specified in the INI file
|
|
process_servers() {
|
|
|
|
local action="$1" # "stop", "start", or "restart"
|
|
local server port settings config mod_directory use_whitelist
|
|
|
|
while IFS= read -r line || [ -n "$line" ]; do
|
|
if [[ $line =~ ^\[([^\]]+)\]$ ]]; then
|
|
server="${BASH_REMATCH[1]}"
|
|
elif [[ $line =~ ^port=([0-9]+)$ ]]; then
|
|
port="${BASH_REMATCH[1]}"
|
|
elif [[ $line =~ ^settings=(.+)$ ]]; then
|
|
settings="${BASH_REMATCH[1]}"
|
|
elif [[ $line =~ ^config=(.+)$ ]]; then
|
|
config="${BASH_REMATCH[1]}"
|
|
elif [[ $line =~ ^mod_directory=(.+)$ ]]; then
|
|
mod_directory="${BASH_REMATCH[1]}"
|
|
elif [[ $line =~ ^use_whitelist=(.+)$ ]]; then
|
|
use_whitelist="${BASH_REMATCH[1]}"
|
|
if [ "$action" = "stop" ]; then
|
|
stop_server "$server"
|
|
elif [ "$action" = "start" ]; then
|
|
start_server "$server" "$port" "$settings" "$config" "$mod_directory" "$use_whitelist"
|
|
elif [ "$action" = "restart" ]; then
|
|
stop_server "$server"
|
|
start_server "$server" "$port" "$settings" "$config" "$mod_directory" "$use_whitelist"
|
|
fi
|
|
fi
|
|
done < "$CONFIG_FILE"
|
|
}
|
|
|
|
# Argument handling
|
|
if [ "$1" = "--help" ]; then
|
|
echo -e "${BOLD}Usage:${RESET}"
|
|
echo -e " ${YELLOW}--update${RESET} : Stop all servers, update, then start each server sequentially"
|
|
echo -e " ${YELLOW}--stop${RESET} : Stop all servers sequentially"
|
|
exit 0
|
|
fi
|
|
|
|
if [ "$1" = "--stop" ]; then
|
|
section "🛑 Stopping All Servers"
|
|
process_servers "stop"
|
|
section "🧹 Cleaning up Screens"
|
|
screen -wipe > /dev/null 2>&1
|
|
status "Below is the list of active screen sessions. Each running server should appear here. If you don't see a server, it may not be running." "$YELLOW"
|
|
screen -ls
|
|
exit 0
|
|
fi
|
|
|
|
if [ "$1" = "--update" ]; then
|
|
section "🛑 Stopping All Servers"
|
|
process_servers "stop"
|
|
update_factorio
|
|
section "🚀 Starting All Servers"
|
|
process_servers "start"
|
|
section "🧹 Cleaning up Screens"
|
|
screen -wipe > /dev/null 2>&1
|
|
status "Below is the list of active screen sessions. Each running server should appear here. If you don't see a server, it may not be running." "$YELLOW"
|
|
screen -ls
|
|
exit 0
|
|
fi
|
|
|
|
# Default: restart each server sequentially (stop, then start)
|
|
section "🔄 Restarting All Servers Sequentially"
|
|
process_servers "restart"
|
|
section "🧹 Cleaning up Screens"
|
|
screen -wipe > /dev/null 2>&1
|
|
status "Below is the list of active screen sessions. Each running server should appear here. If you don't see a server, it may not be running." "$YELLOW"
|
|
screen -ls
|
|
|
|
# After showing screens, check and display each server's ready status
|
|
while IFS= read -r line || [ -n "$line" ]; do
|
|
if [[ $line =~ ^\[([^\]]+)\]$ ]]; then
|
|
server="${BASH_REMATCH[1]}"
|
|
enabled=1
|
|
elif [[ $line =~ ^use_whitelist=(.+)$ ]]; then
|
|
use_whitelist="${BASH_REMATCH[1]}"
|
|
if [ "$enabled" = "1" ]; then
|
|
status_file="/tmp/factorio_server_ready_${server}"
|
|
if [ -f "$status_file" ]; then
|
|
status "$server is ONLINE and ready for connections!" "$GREEN"
|
|
else
|
|
status "Waiting for $server to be ready for connections..." "$YELLOW"
|
|
# Wait up to 2 minutes for the status file to appear
|
|
if timeout 120 bash -c "while [ ! -f '$status_file' ]; do sleep 1; done"; then
|
|
status "$server is ONLINE and ready for connections!" "$GREEN"
|
|
else
|
|
status "Timeout: $server did not report as online within 2 minutes." "$RED"
|
|
fi
|
|
fi
|
|
rm -f "$status_file"
|
|
fi
|
|
enabled=0
|
|
fi
|
|
done < "$CONFIG_FILE"
|
|
|
|
exit 0
|