From f9fe3be0aee2d3d5e4cb7e03401bc3dd7cb22c9e Mon Sep 17 00:00:00 2001 From: Clay Date: Tue, 29 Jul 2025 13:55:36 -0400 Subject: [PATCH] New version --- Factorio/screenstart.sh | 388 ++++++++++++++++++++++------------------ 1 file changed, 214 insertions(+), 174 deletions(-) diff --git a/Factorio/screenstart.sh b/Factorio/screenstart.sh index 8aa4ca7..8f8b2a6 100644 --- a/Factorio/screenstart.sh +++ b/Factorio/screenstart.sh @@ -1,201 +1,241 @@ #!/bin/bash -#ClayGarth.com -game=factorio +# 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' -############################## SAVE AND STOP FUNCTIONS ###################### -stop() { - echo "Stopping $server server." - - # Try to save before forcing the screen closed. - screen -p 0 -S $server -X eval "stuff /quit\015" >> /dev/null 2>&1 - - LOG_FILE="/home/$game/servers/$server/factorio-current.log" - MONITOR_STRING="Goodbye" - - echo "Monitoring the $server server's log file for save confirmation." - - # Check if the monitor string is already present in the log file - if grep -q "$MONITOR_STRING" "$LOG_FILE"; then - echo "The $server server was already stopped!" +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 - # Tail the log file and monitor for the specified string - # Wait for the server to fully save before starting the server instead of force quitting the screen - if timeout 30 tail -n 0 -F "$LOG_FILE" | grep -q "$MONITOR_STRING"; then - echo "The $server server has saved successfully." + 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 - echo "Timeout reached. The $server server did not save within 30 seconds." - screen -S $server -p 0 -X stuff "^C" >> /dev/null 2>&1 + 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 + screen -X -S "$server" quit >> /dev/null 2>&1 sleep 1 fi fi - - - - # Removes the .temp save game to fix loading issues. - # Technically a fix, but it needs to go through each server's files. - cd /home/$game/servers/$server/saves || exit 1 - rm ./*.tmp.zip >> /dev/null 2>&1 - echo "==============================" + # 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" - -stopall(){ - server="test" - stop - - server="ribbon" - stop - - server="family" - stop - - server="private" - stop -} - - -################################ UPDATE FUNCTION ################################## -update(){ -# URL for the Factorio API -FACTORIO_API="https://factorio.com/api/latest-releases" - -# Use curl to get the JSON response from the Factorio API -FACTORIO_RESPONSE=$(curl -s "$FACTORIO_API") - -# Use jq to parse the JSON and extract the stable headless version -FACTORIO_VERSION=$(echo "$FACTORIO_RESPONSE" | jq -r '.stable.headless') - -# Remove periods from the Factorio version number -FACTORIO_VERSION_NO_PERIODS=$(echo "$FACTORIO_VERSION" | tr -d '.') - -# Path to the file storing the current Factorio version -VERSION_FILE="/home/$game/factorio_version.txt" - -# Check if version.txt exists and if the latest Factorio version is newer -if [ -f "$VERSION_FILE" ]; then - CURRENT_VERSION=$(cat "$VERSION_FILE") - - if [ "$FACTORIO_VERSION_NO_PERIODS" -gt "$CURRENT_VERSION" ]; then - echo "Newer Factorio version available. Updating $VERSION_FILE and downloading..." - - # Update version.txt with the new Factorio version - echo "$FACTORIO_VERSION_NO_PERIODS" > "$VERSION_FILE" - - # Update Factorio - cd /home/$game || exit 1 - wget https://www.factorio.com/get-download/stable/headless/linux64 -O factorio.tar.xz - tar -xf factorio.tar.xz - rm -f factorio.tar.xz - #mod updater - #default mods, most servers will use this mod dir - #servers w/ special mods will need a new line under here and a new dir created for them. - /usr/bin/python3 /home/factorio/mod_updater.py -s /home/factorio/servers/Master/server-settings.json -m /home/factorio/mods/default --token 2674c79ebc4fb9e04c29 --username clash --fact-path /home/factorio/factorio/bin/x64/factorio --update - #/usr/bin/python3 /home/factorio/mod_updater.py -s /home/factorio/servers/Master/server-settings.json -m /home/factorio/mods/dad --token 2674fb9e04c29 --username clash --fact-path /home/factorio/factorio/bin/x64/factorio --update - - else - echo "Factorio is already up-to-date. No need to download an update." - echo "==============================" + 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 -else - # Create version.txt if it doesn't exist - echo "$FACTORIO_VERSION_NO_PERIODS" > "$VERSION_FILE" - echo "Factorio version file created." -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 -################################ BASH ARGUMENTS ################################ - -if [ "$1" = "--update" ]; -then - update - echo "updated" -fi - -if [ "$1" = "--help" ]; -then - echo "--update or --stop" - exit + 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 - stopall - exit +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 - -################################ ISSUE FIXES ################################ - -#fixes perms issues -chown -R $game:$game /home/$game/ > /dev/null 2>&1 -chmod -R 755 /home/factorio/mods > /dev/null 2>&1 -chmod +x /home/$game/factorio/bin/x64/factorio > /dev/null 2>&1 -#Copy mod settings, they sometimes get overwritten -cp /home/factorio/mods/mod-settings.dat /home/factorio/mods/default/ > /dev/null 2>&1 - - - -######################################### UPDATE &RESTART Servers ########################################### - - - - -#Starts a screen session for each server. -#Change --server-settings , --config and --port for each server. -#Do NOT put $start in quotes when starting the screen. Even if ShellCheck tells you to. -cd /home/$game/factorio/bin/x64/ || exit 1 - -#Stop all servers -stopall - -#Update Factorio if needed -update - -#Start all servers - -#TEST SERVER -server='test' -port='34198' -start="/home/$game/factorio/bin/x64/factorio --start-server-load-latest --server-settings /home/factorio/servers/$server/server-settings.json --config /home/factorio/servers/$server/config.ini --executable-path /home/factorio/factorio/bin/x64/ --mod-directory /home/factorio/mods/default/ --port $port" -echo "Starting test Server" -/usr/bin/screen -dmS $server $start - - -#RIBBON SERVER -server='ribbon' -port='34196' -start="/home/$game/factorio/bin/x64/factorio --start-server-load-latest --server-settings /home/factorio/servers/$server/server-settings.json --config /home/factorio/servers/$server/config.ini --executable-path /home/factorio/factorio/bin/x64/ --mod-directory /home/factorio/mods/default/ --port $port" -#echo "Starting ribbon Server" -#/usr/bin/screen -dmS $server $start - - -#FAMILY SERVER -server='family' -port='34197' -start="/home/$game/factorio/bin/x64/factorio --start-server-load-latest --server-settings /home/factorio/servers/$server/server-settings.json --config /home/factorio/servers/$server/config.ini --executable-path /home/factorio/factorio/bin/x64/ --mod-directory /home/factorio/mods/default/ --port $port" -echo "Starting family Server" -/usr/bin/screen -dmS $server $start - - -#PRIVATE SERVER -server='private' -port='34199' -start="/home/$game/factorio/bin/x64/factorio --start-server-load-latest --server-settings /home/factorio/servers/$server/server-settings.json --config /home/factorio/servers/$server/config.ini --executable-path /home/factorio/factorio/bin/x64/ --mod-directory /home/factorio/mods/default/ --port $port" -echo "Starting private Server" -/usr/bin/screen -dmS $server $start - - -echo "==============================" +# 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 -echo "==============================" +# 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