diff --git a/Dockerfile b/Dockerfile index 87acb8d..6c4a86b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,4 +10,4 @@ RUN chmod +x /entrypoint.sh USER container WORKDIR /home/container -ENTRYPOINT ["/entrypoint.sh"] \ No newline at end of file +ENTRYPOINT ["/usr/bin/tini", "-g", "--", "/entrypoint.sh"] \ No newline at end of file diff --git a/egg-avorion-2.json b/egg-avorion-2.json new file mode 100644 index 0000000..862a264 --- /dev/null +++ b/egg-avorion-2.json @@ -0,0 +1,204 @@ +{ + "_comment": "DO NOT EDIT: FILE GENERATED AUTOMATICALLY BY PTERODACTYL PANEL - PTERODACTYL.IO", + "meta": { + "version": "PTDL_v2", + "update_url": "https:\/\/pterodactyleggs.com\/egg\/6735ff404924a4e9bbcb806a\/download\/egg-avorion.json" + }, + "exported_at": "2026-04-25T04:06:06+00:00", + "name": "Avorion", + "author": "iamkubi@gmail.com", + "description": "A procedural co-op space sandbox where players can build their own space ships out of dynamically scalable blocks. Fight epic space battles, explore, mine, trade, wage wars and build your own empire to save your galaxy from being torn apart by an unknown enemy.", + "features": [ + "steam_disk_space" + ], + "docker_images": { + "git.easygoingaming.com\/davoguha\/avorion-steamcmd-nsswrap:latest": "git.easygoingaming.com\/davoguha\/avorion-steamcmd-nsswrap:latest" + }, + "file_denylist": [], + "startup": ".\/bin\/AvorionServer --galaxy-name {{GALAXY_NAME}} --admin {{ADMIN_ID}} --datapath galaxy --port {{SERVER_PORT}} --query-port {{QUERY_PORT}} --steam-master-port {{STEAM_MASTER_PORT}} --steam-query-port {{STEAM_QUERY_PORT}} --max-players {{MAX_PLAYERS}} --difficulty {{DIFFICULTY}} --collision-damage {{COLLISION_DMG}} --save-interval {{SAVE_INTERVAL}} --same-start-sector {{SAME_START_SECTOR}} --server-name \"{{SERVER_NAME}}\" --threads {{GAME_THREADS}} --listed {{SERVER_LISTED}}", + "config": { + "files": "{}", + "startup": "{\r\n \"done\": \"Server startup complete\"\r\n}", + "logs": "{}", + "stop": "\/stop" + }, + "scripts": { + "installation": { + "script": "#!\/bin\/bash\r\n# Avorion Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\n\r\n\r\n## just in case someone removed the defaults.\r\nif [[ \"${STEAM_USER}\" == \"\" ]] || [[ \"${STEAM_PASS}\" == \"\" ]]; then\r\n echo -e \"steam user is not set.\\n\"\r\n echo -e \"Using anonymous user.\\n\"\r\n STEAM_USER=anonymous\r\n STEAM_PASS=\"\"\r\n STEAM_AUTH=\"\"\r\nelse\r\n echo -e \"user set to ${STEAM_USER}\"\r\nfi\r\n\r\n## download and install steamcmd\r\ncd \/tmp\r\nmkdir -p \/mnt\/server\/steamcmd\r\ncurl -sSL -o steamcmd.tar.gz https:\/\/steamcdn-a.akamaihd.net\/client\/installer\/steamcmd_linux.tar.gz\r\ntar -xzvf steamcmd.tar.gz -C \/mnt\/server\/steamcmd\r\nmkdir -p \/mnt\/server\/steamapps # Fix steamcmd disk write error when this folder is missing\r\ncd \/mnt\/server\/steamcmd\r\n\r\n# SteamCMD fails otherwise for some reason, even running as root.\r\n# This is changed at the end of the install process anyways.\r\nchown -R root:root \/mnt\r\nexport HOME=\/mnt\/server\r\n\r\n## install game using steamcmd\r\n.\/steamcmd.sh +force_install_dir \/mnt\/server $( [[ \"${WINDOWS_INSTALL}\" == \"1\" ]] && printf %s '+@sSteamCmdForcePlatformType windows' || printf %s '+@sSteamCmdForcePlatformType linux' ) +login \"${STEAM_USER}\" \"${STEAM_PASS}\" \"${STEAM_AUTH}\" +app_update ${SRCDS_APPID} $( [[ -z ${SRCDS_BETAID} ]] || printf %s \"-beta ${SRCDS_BETAID}\" ) $( [[ -z ${SRCDS_BETAPASS} ]] || printf %s \"-betapassword ${SRCDS_BETAPASS}\" ) ${INSTALL_FLAGS} validate +quit\r\n\r\n## set up 32 bit libraries\r\nmkdir -p \/mnt\/server\/.steam\/sdk32\r\ncp -v linux32\/steamclient.so ..\/.steam\/sdk32\/steamclient.so\r\n\r\n## set up 64 bit libraries\r\nmkdir -p \/mnt\/server\/.steam\/sdk64\r\ncp -v linux64\/steamclient.so ..\/.steam\/sdk64\/steamclient.so\r\n\r\n\r\nmkdir -p \/mnt\/server\/backups\r\nmkdir -p \/mnt\/server\/galaxy\/${GALAXY_NAME}\r\ncurl https:\/\/raw.githubusercontent.com\/ptero-eggs\/game-eggs\/main\/avorion\/server.ini --output \/mnt\/server\/galaxy\/${GALAXY_NAME}\/server.ini\r\n\r\n## install end\r\necho \"-----------------------------------------\"\r\necho \"Installation completed...\"\r\necho \"-----------------------------------------\"", + "container": "ghcr.io\/ptero-eggs\/installers:debian", + "entrypoint": "bash" + } + }, + "variables": [ + { + "name": "Galaxy Name", + "description": "Name of the Galaxy to create", + "env_variable": "GALAXY_NAME", + "default_value": "Avorion", + "user_viewable": true, + "user_editable": true, + "rules": "required|string|max:32", + "field_type": "text" + }, + { + "name": "Server Name", + "description": "The name of the server, shown in the server list.", + "env_variable": "SERVER_NAME", + "default_value": "Avorion Server", + "user_viewable": true, + "user_editable": true, + "rules": "required|string|max:64", + "field_type": "text" + }, + { + "name": "Admin ID", + "description": "Steam64 ID for the player to make Server Admin", + "env_variable": "ADMIN_ID", + "default_value": "", + "user_viewable": true, + "user_editable": true, + "rules": "required|string|max:20", + "field_type": "text" + }, + { + "name": "Max Players", + "description": "Maximum number of players allowed", + "env_variable": "MAX_PLAYERS", + "default_value": "10", + "user_viewable": true, + "user_editable": false, + "rules": "required|int|max:64", + "field_type": "text" + }, + { + "name": "Game Difficulty", + "description": "Difficulty of the server, allowed values are: -3, -2, -1, 0, 1, 2, 3 Default: 0", + "env_variable": "DIFFICULTY", + "default_value": "0", + "user_viewable": true, + "user_editable": true, + "rules": "required|integer|in:0,1,2,3,-1,-2,-3", + "field_type": "text" + }, + { + "name": "Collision Damage", + "description": "A multiplier for damage to colliding objects. Accepts floating-point numbers, e.g. 0.5 is 50% collision damage. 0: no damage, 1: full damage. default: 1", + "env_variable": "COLLISION_DMG", + "default_value": "1", + "user_viewable": true, + "user_editable": true, + "rules": "required|string|max:20", + "field_type": "text" + }, + { + "name": "Save Interval", + "description": "Time between automatic saves in seconds. Defaults to 300 (5 minutes).", + "env_variable": "SAVE_INTERVAL", + "default_value": "300", + "user_viewable": true, + "user_editable": true, + "rules": "required|int", + "field_type": "text" + }, + { + "name": "Same Start Sector", + "description": "Indicates if all players should start in the same sector. If false, a random empty sector on the outer rim is populated and used as the home sector for each new player.", + "env_variable": "SAME_START_SECTOR", + "default_value": "true", + "user_viewable": true, + "user_editable": true, + "rules": "required|string|in:true,false", + "field_type": "text" + }, + { + "name": "Threads", + "description": "Number of concurrent threads that are used to update sectors. (Identical to the 'Threads' setting ingame.)", + "env_variable": "GAME_THREADS", + "default_value": "1", + "user_viewable": true, + "user_editable": true, + "rules": "required|integer|max:20", + "field_type": "text" + }, + { + "name": "List Publicly", + "description": "Privacy setting. If enabled together with useSteam, the server will show up in public server lists. (Same as the ingame setting 'List Publicly')", + "env_variable": "SERVER_LISTED", + "default_value": "true", + "user_viewable": true, + "user_editable": true, + "rules": "required|string|in:true,false", + "field_type": "text" + }, + { + "name": "Steam App ID", + "description": "", + "env_variable": "SRCDS_APPID", + "default_value": "565060", + "user_viewable": false, + "user_editable": false, + "rules": "required|string|in:565060", + "field_type": "text" + }, + { + "name": "LD Library Path", + "description": "", + "env_variable": "LD_LIBRARY_PATH", + "default_value": ".\/linux64", + "user_viewable": false, + "user_editable": false, + "rules": "required|string|max:20", + "field_type": "text" + }, + { + "name": "Steam Master Port", + "description": "", + "env_variable": "STEAM_MASTER_PORT", + "default_value": "27021", + "user_viewable": true, + "user_editable": false, + "rules": "required|string|max:20", + "field_type": "text" + }, + { + "name": "Steam Query Port", + "description": "", + "env_variable": "STEAM_QUERY_PORT", + "default_value": "27020", + "user_viewable": true, + "user_editable": false, + "rules": "required|string|max:20", + "field_type": "text" + }, + { + "name": "Query Port", + "description": "", + "env_variable": "QUERY_PORT", + "default_value": "27003", + "user_viewable": true, + "user_editable": false, + "rules": "required|string|max:20", + "field_type": "text" + }, + { + "name": "Auto Update", + "description": "1 = on; 0 = off", + "env_variable": "AUTO_UPDATE", + "default_value": "1", + "user_viewable": true, + "user_editable": true, + "rules": "required|boolean", + "field_type": "text" + }, + { + "name": "Beta branch", + "description": "Leave empty for the public branch, beta for the beta branch.", + "env_variable": "SRCDS_BETAID", + "default_value": "", + "user_viewable": true, + "user_editable": true, + "rules": "nullable|string|in:,beta", + "field_type": "text" + } + ] +} \ No newline at end of file diff --git a/egg-avorion.json b/egg-avorion.json new file mode 100644 index 0000000..3d6e3df --- /dev/null +++ b/egg-avorion.json @@ -0,0 +1,204 @@ +{ + "_comment": "DO NOT EDIT: FILE GENERATED AUTOMATICALLY BY PTERODACTYL PANEL - PTERODACTYL.IO", + "meta": { + "version": "PTDL_v2", + "update_url": "https:\/\/pterodactyleggs.com\/egg\/6735ff404924a4e9bbcb806a\/download\/egg-avorion.json" + }, + "exported_at": "2026-02-12T00:22:58+00:00", + "name": "Avorion", + "author": "iamkubi@gmail.com", + "description": "A procedural co-op space sandbox where players can build their own space ships out of dynamically scalable blocks. Fight epic space battles, explore, mine, trade, wage wars and build your own empire to save your galaxy from being torn apart by an unknown enemy.", + "features": [ + "steam_disk_space" + ], + "docker_images": { + "ghcr.io\/ptero-eggs\/steamcmd:debian": "ghcr.io\/ptero-eggs\/steamcmd:debian" + }, + "file_denylist": [], + "startup": ".\/bin\/AvorionServer --galaxy-name {{GALAXY_NAME}} --admin {{ADMIN_ID}} --datapath galaxy --port {{SERVER_PORT}} --query-port {{QUERY_PORT}} --steam-master-port {{STEAM_MASTER_PORT}} --steam-query-port {{STEAM_QUERY_PORT}} --max-players {{MAX_PLAYERS}} --difficulty {{DIFFICULTY}} --collision-damage {{COLLISION_DMG}} --save-interval {{SAVE_INTERVAL}} --same-start-sector {{SAME_START_SECTOR}} --server-name \"{{SERVER_NAME}}\" --threads {{GAME_THREADS}} --listed {{SERVER_LISTED}}", + "config": { + "files": "{}", + "startup": "{\r\n \"done\": \"Server startup complete\"\r\n}", + "logs": "{}", + "stop": "\/stop" + }, + "scripts": { + "installation": { + "script": "#!\/bin\/bash\r\n# Avorion Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\n\r\n\r\n## just in case someone removed the defaults.\r\nif [[ \"${STEAM_USER}\" == \"\" ]] || [[ \"${STEAM_PASS}\" == \"\" ]]; then\r\n echo -e \"steam user is not set.\\n\"\r\n echo -e \"Using anonymous user.\\n\"\r\n STEAM_USER=anonymous\r\n STEAM_PASS=\"\"\r\n STEAM_AUTH=\"\"\r\nelse\r\n echo -e \"user set to ${STEAM_USER}\"\r\nfi\r\n\r\n## download and install steamcmd\r\ncd \/tmp\r\nmkdir -p \/mnt\/server\/steamcmd\r\ncurl -sSL -o steamcmd.tar.gz https:\/\/steamcdn-a.akamaihd.net\/client\/installer\/steamcmd_linux.tar.gz\r\ntar -xzvf steamcmd.tar.gz -C \/mnt\/server\/steamcmd\r\nmkdir -p \/mnt\/server\/steamapps # Fix steamcmd disk write error when this folder is missing\r\ncd \/mnt\/server\/steamcmd\r\n\r\n# SteamCMD fails otherwise for some reason, even running as root.\r\n# This is changed at the end of the install process anyways.\r\nchown -R root:root \/mnt\r\nexport HOME=\/mnt\/server\r\n\r\n## install game using steamcmd\r\n.\/steamcmd.sh +force_install_dir \/mnt\/server $( [[ \"${WINDOWS_INSTALL}\" == \"1\" ]] && printf %s '+@sSteamCmdForcePlatformType windows' || printf %s '+@sSteamCmdForcePlatformType linux' ) +login \"${STEAM_USER}\" \"${STEAM_PASS}\" \"${STEAM_AUTH}\" +app_update ${SRCDS_APPID} $( [[ -z ${SRCDS_BETAID} ]] || printf %s \"-beta ${SRCDS_BETAID}\" ) $( [[ -z ${SRCDS_BETAPASS} ]] || printf %s \"-betapassword ${SRCDS_BETAPASS}\" ) ${INSTALL_FLAGS} validate +quit\r\n\r\n## set up 32 bit libraries\r\nmkdir -p \/mnt\/server\/.steam\/sdk32\r\ncp -v linux32\/steamclient.so ..\/.steam\/sdk32\/steamclient.so\r\n\r\n## set up 64 bit libraries\r\nmkdir -p \/mnt\/server\/.steam\/sdk64\r\ncp -v linux64\/steamclient.so ..\/.steam\/sdk64\/steamclient.so\r\n\r\n\r\nmkdir -p \/mnt\/server\/backups\r\nmkdir -p \/mnt\/server\/galaxy\/${GALAXY_NAME}\r\ncurl https:\/\/raw.githubusercontent.com\/ptero-eggs\/game-eggs\/main\/avorion\/server.ini --output \/mnt\/server\/galaxy\/${GALAXY_NAME}\/server.ini\r\n\r\n## install end\r\necho \"-----------------------------------------\"\r\necho \"Installation completed...\"\r\necho \"-----------------------------------------\"", + "container": "ghcr.io\/ptero-eggs\/installers:debian", + "entrypoint": "bash" + } + }, + "variables": [ + { + "name": "Galaxy Name", + "description": "Name of the Galaxy to create", + "env_variable": "GALAXY_NAME", + "default_value": "Avorion", + "user_viewable": true, + "user_editable": true, + "rules": "required|string|max:32", + "field_type": "text" + }, + { + "name": "Server Name", + "description": "The name of the server, shown in the server list.", + "env_variable": "SERVER_NAME", + "default_value": "Avorion Server", + "user_viewable": true, + "user_editable": true, + "rules": "required|string|max:64", + "field_type": "text" + }, + { + "name": "Admin ID", + "description": "Steam64 ID for the player to make Server Admin", + "env_variable": "ADMIN_ID", + "default_value": "", + "user_viewable": true, + "user_editable": true, + "rules": "required|string|max:20", + "field_type": "text" + }, + { + "name": "Max Players", + "description": "Maximum number of players allowed", + "env_variable": "MAX_PLAYERS", + "default_value": "10", + "user_viewable": true, + "user_editable": false, + "rules": "required|int|max:64", + "field_type": "text" + }, + { + "name": "Game Difficulty", + "description": "Difficulty of the server, allowed values are: -3, -2, -1, 0, 1, 2, 3 Default: 0", + "env_variable": "DIFFICULTY", + "default_value": "0", + "user_viewable": true, + "user_editable": true, + "rules": "required|integer|in:0,1,2,3,-1,-2,-3", + "field_type": "text" + }, + { + "name": "Collision Damage", + "description": "A multiplier for damage to colliding objects. Accepts floating-point numbers, e.g. 0.5 is 50% collision damage. 0: no damage, 1: full damage. default: 1", + "env_variable": "COLLISION_DMG", + "default_value": "1", + "user_viewable": true, + "user_editable": true, + "rules": "required|string|max:20", + "field_type": "text" + }, + { + "name": "Save Interval", + "description": "Time between automatic saves in seconds. Defaults to 300 (5 minutes).", + "env_variable": "SAVE_INTERVAL", + "default_value": "300", + "user_viewable": true, + "user_editable": true, + "rules": "required|int", + "field_type": "text" + }, + { + "name": "Same Start Sector", + "description": "Indicates if all players should start in the same sector. If false, a random empty sector on the outer rim is populated and used as the home sector for each new player.", + "env_variable": "SAME_START_SECTOR", + "default_value": "true", + "user_viewable": true, + "user_editable": true, + "rules": "required|string|in:true,false", + "field_type": "text" + }, + { + "name": "Threads", + "description": "Number of concurrent threads that are used to update sectors. (Identical to the 'Threads' setting ingame.)", + "env_variable": "GAME_THREADS", + "default_value": "1", + "user_viewable": true, + "user_editable": true, + "rules": "required|integer|max:20", + "field_type": "text" + }, + { + "name": "List Publicly", + "description": "Privacy setting. If enabled together with useSteam, the server will show up in public server lists. (Same as the ingame setting 'List Publicly')", + "env_variable": "SERVER_LISTED", + "default_value": "true", + "user_viewable": true, + "user_editable": true, + "rules": "required|string|in:true,false", + "field_type": "text" + }, + { + "name": "Steam App ID", + "description": "", + "env_variable": "SRCDS_APPID", + "default_value": "565060", + "user_viewable": false, + "user_editable": false, + "rules": "required|string|in:565060", + "field_type": "text" + }, + { + "name": "LD Library Path", + "description": "", + "env_variable": "LD_LIBRARY_PATH", + "default_value": ".\/linux64", + "user_viewable": false, + "user_editable": false, + "rules": "required|string|max:20", + "field_type": "text" + }, + { + "name": "Steam Master Port", + "description": "", + "env_variable": "STEAM_MASTER_PORT", + "default_value": "27021", + "user_viewable": true, + "user_editable": false, + "rules": "required|string|max:20", + "field_type": "text" + }, + { + "name": "Steam Query Port", + "description": "", + "env_variable": "STEAM_QUERY_PORT", + "default_value": "27020", + "user_viewable": true, + "user_editable": false, + "rules": "required|string|max:20", + "field_type": "text" + }, + { + "name": "Query Port", + "description": "", + "env_variable": "QUERY_PORT", + "default_value": "27003", + "user_viewable": true, + "user_editable": false, + "rules": "required|string|max:20", + "field_type": "text" + }, + { + "name": "Auto Update", + "description": "1 = on; 0 = off", + "env_variable": "AUTO_UPDATE", + "default_value": "1", + "user_viewable": true, + "user_editable": true, + "rules": "required|boolean", + "field_type": "text" + }, + { + "name": "Beta branch", + "description": "Leave empty for the public branch, beta for the beta branch.", + "env_variable": "SRCDS_BETAID", + "default_value": "", + "user_viewable": true, + "user_editable": true, + "rules": "nullable|string|in:,beta", + "field_type": "text" + } + ] +} \ No newline at end of file diff --git a/entrypoint.sh b/entrypoint.sh index f35c4b3..76c78f9 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,5 +1,7 @@ #!/bin/bash -set -euo pipefail +# NSS wrapper for Avorion getpwuid(); then match upstream Ptero steamcmd entrypoint behavior +# (see https://github.com/Ptero-Eggs/yolks/blob/main/steamcmd/entrypoint.sh ) +set -eo pipefail export USER=container export LOGNAME=container @@ -36,7 +38,7 @@ else echo "[entrypoint] WARNING: libnss_wrapper not found; UID/GID passthrough may fail for Avorion." >&2 fi -cd /home/container +cd /home/container || exit 1 echo "[entrypoint] uid=${uid} gid=${gid} home=${HOME} user=${USER}" >&2 echo "[entrypoint] NSS wrapper passwd=${NSS_WRAPPER_PASSWD} group=${NSS_WRAPPER_GROUP}" >&2 @@ -45,9 +47,53 @@ if ! getent passwd "$uid" >/dev/null 2>&1; then echo "[entrypoint] WARNING: getent cannot resolve uid ${uid} prior to exec." >&2 fi -if [ -n "${STARTUP:-}" ]; then - echo ":/home/container$ ${STARTUP}" - exec /bin/bash -c "${STARTUP}" +# --- below: adapted from Ptero-Eggs/yolks steamcmd/entrypoint.sh --- + +sleep 1 + +TZ=${TZ:-UTC} +export TZ + +INTERNAL_IP=$(ip route get 1 | awk '{print $(NF-2);exit}') +export INTERNAL_IP + +# Set environment for Steam Proton (unchanged from upstream) +if [ -f "/usr/local/bin/proton" ]; then + if [ -n "${SRCDS_APPID:-}" ]; then + mkdir -p "/home/container/.steam/steam/steamapps/compatdata/${SRCDS_APPID}" + export STEAM_COMPAT_CLIENT_INSTALL_PATH="/home/container/.steam/steam" + export STEAM_COMPAT_DATA_PATH="/home/container/.steam/steam/steamapps/compatdata/${SRCDS_APPID}" + export PATH="${PATH}:/root/.local/bin" + else + echo -e "----------------------------------------------------------------------------------" + echo -e "WARNING!!! SRCDS_APPID is missing and must be set when using Proton" + echo -e "Server will now terminate" + echo -e "----------------------------------------------------------------------------------" + exit 1 + fi fi -exec "$@" \ No newline at end of file +STEAM_USER=${STEAM_USER:-anonymous} +if [ "${STEAM_USER}" == "anonymous" ]; then + STEAM_PASS="" + STEAM_AUTH="" +fi + +if [ -z "${AUTO_UPDATE}" ] || [ "${AUTO_UPDATE}" == "1" ]; then + if [ -n "${SRCDS_APPID:-}" ] && [ -x "./steamcmd/steamcmd.sh" ]; then + # shellcheck disable=SC2046,SC2086 + ./steamcmd/steamcmd.sh +force_install_dir /home/container \ + $([[ "${WINDOWS_INSTALL:-}" == "1" ]] && printf %s '+@sSteamCmdForcePlatformType windows' || printf %s '+@sSteamCmdForcePlatformType linux') \ + +login "${STEAM_USER}" "${STEAM_PASS}" "${STEAM_AUTH}" \ + $([[ -z ${HLDS_GAME:-} ]] || printf %s "+app_set_config 90 mod ${HLDS_GAME}") \ + "+app_update ${SRCDS_APPID} $([[ -z ${SRCDS_BETAID:-} ]] || printf %s "-beta ${SRCDS_BETAID}") $([[ -z ${SRCDS_BETAPASS:-} ]] || printf %s "-betapassword ${SRCDS_BETAPASS}") ${INSTALL_FLAGS:-} $([[ "${VALIDATE:-}" == "1" ]] && printf %s 'validate')" \ + $([[ "${UPDATE_STEAMWORKS:-}" == "1" ]] && printf %s '+app_update 1007') +quit + fi +fi + +# Replace {{VAR}} with ${VAR} then eval (required for Pterodactyl egg startup strings) +MODIFIED_STARTUP=$(echo "${STARTUP}" | sed -e 's/{{/${/g' -e 's/}}/}/g') +echo -e ":/home/container$ ${MODIFIED_STARTUP}" + +# shellcheck disable=SC2086 +eval ${MODIFIED_STARTUP}