mirror of
https://ceregatti.org/git/daniel/dayzdockerserver.git
synced 2025-05-06 22:31:18 +00:00

Remove loop to allow docker to handle restarts on crashes. Hacks exist for now to force exit 0 because the server always crashes on exit. Rework how the config is loaded. It need not always happen.
430 lines
12 KiB
Bash
Executable file
430 lines
12 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
|
|
# Colors
|
|
default="\e[0m"
|
|
red="\e[31m"
|
|
green="\e[32m"
|
|
yellow="\e[93m"
|
|
lightblue="\e[94m"
|
|
blue="\e[34m"
|
|
magenta="\e[35m"
|
|
cyan="\e[36m"
|
|
|
|
# Make sure to report and clean up on exit, as these files remain in the container's volume
|
|
function report() {
|
|
echo
|
|
echo -e "${yellow}========================================== error.log =========================================="
|
|
find "${HOME}" -name error.log -exec head {} \; -exec rm -f {} \;
|
|
echo
|
|
echo -e "${yellow}========================================== script*.log ========================================"
|
|
find "${HOME}" -name "script*.log" -exec head {} \; -exec rm -f {} \;
|
|
echo
|
|
echo -e "${yellow}========================================== *.RPT =============================================="
|
|
find "${HOME}" -name "*.RPT" -exec ls -la {} \; -exec rm -f {} \;
|
|
echo
|
|
echo -e "${yellow}========================================== End crash log ======================================"
|
|
}
|
|
|
|
# Make sure we don't start collecting core files
|
|
# FIXME Set this in Docker somewhere
|
|
ulimit -c 0
|
|
|
|
# DayZ Experimental SteamID, because there is no release version of the Linux server yet
|
|
appid=1042420
|
|
|
|
# DayZ Release SteamID. This is for mods, as only the release has them.
|
|
dayz_id=221100
|
|
|
|
# Command line argument variables
|
|
# Server config file
|
|
config=serverDZ.cfg
|
|
# Server port
|
|
port=2302
|
|
rcon_port=2303
|
|
# Server profile directory
|
|
profile="-profiles=${HOME}/serverprofile/"
|
|
# To log or not to log.
|
|
# All possible logging on:
|
|
#logs="-dologs -adminlog -netlog"
|
|
# No logs? This should read "-somelogs"
|
|
logs="-nologs"
|
|
|
|
# Mods. WIP. This will have to come from another file, as the plan is to manage this with
|
|
# this very script.
|
|
# mods="@CF;@community-Online-Tools;@Banov;@SimpleAutorun"
|
|
mods=""
|
|
|
|
# Put them all together
|
|
dayzparameter=" -config=${config} -port=${port} -mod='${mods}' -freezecheck -fps=60 -BEpath=${HOME}/serverfiles/battleye ${profile} ${logs}"
|
|
|
|
# Base directories
|
|
CFG_SRC_FILES="/files"
|
|
SERVER_FILES="${HOME}/serverfiles"
|
|
SERVER_PROFILE="${HOME}/serverprofile"
|
|
|
|
# Server configuration file
|
|
SERVER_CFG_FILE="serverDZ.cfg"
|
|
SERVER_CFG_DST="${SERVER_FILES}/${SERVER_CFG_FILE}"
|
|
SERVER_CFG_SRC="${CFG_SRC_FILES}/${SERVER_CFG_FILE}"
|
|
|
|
# Used to check if dayZ is installed
|
|
SERVER_INSTALL_FILE="${SERVER_FILES}/DayZServer"
|
|
|
|
# Steam files
|
|
STEAM_LOGIN="${HOME}/steamlogin"
|
|
STEAMCMD=steamcmd
|
|
|
|
# Workshop
|
|
WORKSHOP_CFG="${HOME}/workshop.cfg"
|
|
|
|
# Other stuff
|
|
YES="${green}yes${default}"
|
|
NO="${red}no${default}"
|
|
|
|
fn_usage(){
|
|
echo -e "
|
|
${red}Bad option or arguments! ${yellow}${*}${default}
|
|
|
|
Usage: ${green}$(basename $0)${yellow} option [ arg1 [ arg2 ] ]
|
|
|
|
Options and arguments:
|
|
|
|
install - Install the DayZ server files
|
|
login - Login to Steam
|
|
rcon - Connect to the server using a python RCON client
|
|
status - Shows the server's status as well as the state of the server files and mods (Needs install, update, etc.)
|
|
stop - Stop the server
|
|
update - Update the DayZ server files
|
|
workshop - Workshop Features
|
|
activate id [id...] - Activate one or many installed DayZ Workshop item by id
|
|
add id [id...] - Add one or many DayZ Workshop items by id
|
|
deactivate id [id...] - Deactivate one or many installed DayZ Workshop items by id - Keeps the addon files but excludes from -mod=
|
|
list - List Workshop items and their states (Active vs. Non)
|
|
remove id [id...] - Remove one or many Workshop items by id
|
|
${default}"
|
|
exit 1
|
|
}
|
|
|
|
fn_prompt_yn(){
|
|
echo -n "${1} (y|N) " >&2
|
|
read -s -n 1 a
|
|
a=$(echo ${a} | tr A-Z a-z)
|
|
if [[ "${a}" = "y" ]]
|
|
then
|
|
echo
|
|
return 0
|
|
else
|
|
echo
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
fn_loadconfig_dayz(){
|
|
if [ ! -f "${SERVER_INSTALL_FILE}" ]
|
|
then
|
|
echo
|
|
echo -e "The DayZ server files are not installed. Run '${green}docker-compose run --rm main dayzserver install${default}'"
|
|
echo
|
|
exit 1
|
|
fi
|
|
# Handle the initial server configuration file
|
|
if [ ! -f ${SERVER_CFG_DST} ]
|
|
then
|
|
echo "Creating initial server configuration file"
|
|
cp "${SERVER_CFG_SRC}" "${SERVER_CFG_DST}"
|
|
fi
|
|
# battleye config and rconpassword setup
|
|
# The server creates a new file from this file, which it then uses.
|
|
# Let's make sure to delete it first
|
|
BE_SERVER_FILE="${HOME}/serverfiles/battleye/beserver_x64.cfg"
|
|
ALT_BE_SERVER_FILE=$(find ${HOME}/serverfiles/battleye -name "beserver_x64_active*")
|
|
if [ ! -f "${BE_SERVER_FILE}" ] && [ ! -f "${ALT_BE_SERVER_FILE}" ]
|
|
then
|
|
passwd=$(openssl rand -base64 8 | tr -dc 'A-Za-z0-9')
|
|
if [ "${passwd}" == "" ]; then
|
|
passwd=$(< /dev/urandom tr -dc 'A-Za-z0-9' | head -c10)
|
|
fi
|
|
if [ "${passwd}" == "" ]; then
|
|
printf "[ ${red}FAIL${default} ] Could not generate a passwort for RCON!\nOpen the Battleye config with 'dayzserver rcon'."
|
|
exit 1
|
|
else
|
|
cat > "${BE_SERVER_FILE}" <<EOF
|
|
RConPassword ${passwd}
|
|
RestrictRCon 0
|
|
RConPort ${rcon_port}
|
|
EOF
|
|
fi
|
|
printf "[ ${cyan}INFO${default} ] New RCON password: ${yellow}${passwd}${default}\n"
|
|
else
|
|
if [ -f "${BE_SERVER_FILE}" ]
|
|
then
|
|
FILE="${BE_SERVER_FILE}"
|
|
elif [ -f "${ALT_BE_SERVER_FILE}" ]
|
|
then
|
|
FILE="${ALT_BE_SERVER_FILE}"
|
|
fi
|
|
passwd=$(grep RConPassword ${FILE} | awk '{print $2}')
|
|
# printf "[ ${cyan}INFO${default} ] Using existing RCON password: ${yellow}${passwd}${default}\n"
|
|
fi
|
|
cp /usr/local/py3rcon/configexample.json ~/py3rcon.config.json
|
|
jq --arg port 2303 --arg rcon_password b0fNIBVfkM \
|
|
'.logfile="py3rcon.log" | .loglevel=0 | .server.port=$port | .server.rcon_password=$rcon_password | del(.repeatMessage)' \
|
|
/usr/local/py3rcon/configexample.json \
|
|
> ~/py3rcon.config.json
|
|
}
|
|
|
|
fn_start_dayz(){
|
|
# Check for interactive shell
|
|
if [ -t 0 ]
|
|
then
|
|
echo
|
|
echo -e "Not starting the server in an interactive shell. Start the server using '${green}docker-compose up -d${default}'"
|
|
echo
|
|
exit
|
|
fi
|
|
# Do the report on exit. Set here so that it only happens once we're starting the server, and not for other actions.
|
|
trap '
|
|
report
|
|
' EXIT
|
|
fn_workshop_mods
|
|
cd ${SERVER_FILES}
|
|
# Run the server. Allow docker to restart the container if the script exits with a code other than 0. This is so we can
|
|
# safely shut the container down without killing the server within.
|
|
printf "[ ${green}DayZ${default} ] Server starting...\n"
|
|
./DayZServer $dayzparameter
|
|
EXIT_CODE=$?
|
|
if [[ ${EXIT_CODE} = "139" ]]
|
|
then
|
|
EXIT_CODE=0
|
|
fi
|
|
printf "[ ${yellow}DayZ${default} ] Server stopped. Exit code: ${EXIT_CODE}\n"
|
|
exit ${EXIT_CODE}
|
|
}
|
|
|
|
fn_stop_dayz(){
|
|
echo "Stopping DayZ server...(this is not implemented)"
|
|
}
|
|
|
|
fn_steam_login(){
|
|
if [ -f "${STEAM_LOGIN}" ]
|
|
then
|
|
if fn_prompt_yn "The steam login is already set. Reset it?"
|
|
then
|
|
rm -f "${STEAM_LOGIN}"
|
|
else
|
|
echo "Not reset."
|
|
exit 0
|
|
fi
|
|
fi
|
|
if [ ! -f "${STEAM_LOGIN}" ]
|
|
then
|
|
echo "Setting up Steam credentials"
|
|
echo -n "Steam Username (anonymous): "
|
|
read steamlogin
|
|
if [[ "${steamlogin}" = "" ]]
|
|
then
|
|
echo "Steam login set to 'anonymous'"
|
|
steamlogin="anonymous"
|
|
fi
|
|
echo "steamlogin=${steamlogin}" > "${STEAM_LOGIN}"
|
|
${STEAMCMD} +force_install_dir ${SERVER_FILES} +login "${steamlogin}" +quit
|
|
fi
|
|
}
|
|
|
|
fn_steamlogin_dayz(){
|
|
if [ -f "${STEAM_LOGIN}" ]
|
|
then
|
|
source "${STEAM_LOGIN}"
|
|
else
|
|
echo "No cached Steam credentials. Please configure this now: "
|
|
fn_steam_login
|
|
fi
|
|
}
|
|
|
|
fn_runvalidate_dayz(){
|
|
# fn_loadconfig_dayz
|
|
${STEAMCMD} +force_install_dir ${SERVER_FILES} +login "${steamlogin}" +app_update "${appid}" validate +quit
|
|
}
|
|
|
|
fn_install_dayz(){
|
|
if [ ! -f "${SERVER_INSTALL_FILE}" ]; then
|
|
mkdir -p "${SERVER_FILES}"
|
|
mkdir -p "${SERVER_PROFILE}"
|
|
printf "[ ${yellow}DayZ${default} ] Downloading DayZ Server-Files!\n"
|
|
fn_steamlogin_dayz
|
|
fn_runvalidate_dayz
|
|
else
|
|
printf "[ ${lightblue}DayZ${default} ] The Server is already installed.\n"
|
|
fi
|
|
}
|
|
|
|
fn_runupdate_dayz(){
|
|
if ! diff -q "${SERVER_CFG_SRC}" "${SERVER_CFG_DST}"
|
|
then
|
|
echo "========================================================================="
|
|
diff -Nau --color "${SERVER_CFG_SRC}" "${SERVER_CFG_DST}" || echo ""
|
|
echo "========================================================================="
|
|
if fn_prompt_yn "The new server configuration file differs from what's installed. Use it?"
|
|
then
|
|
echo "Updating the server configuration file"
|
|
cp "${SERVER_CFG_SRC}" "${SERVER_CFG_DST}"
|
|
else
|
|
echo "NOT updating the server configuration file"
|
|
fi
|
|
fi
|
|
${STEAMCMD} +force_install_dir ${SERVER_FILES} +login "${steamlogin}" +app_update "${appid}" +quit
|
|
}
|
|
|
|
fn_update_dayz(){
|
|
fn_steamlogin_dayz
|
|
appmanifestfile=${SERVER_FILES}/steamapps/appmanifest_"${appid}".acf
|
|
printf "[ ... ] Checking for update:"
|
|
# gets currentbuild
|
|
currentbuild=$(grep buildid "${appmanifestfile}" | tr '[:blank:]"' ' ' | tr -s ' ' | cut -d \ -f3)
|
|
# Removes appinfo.vdf as a fix for not always getting up to date version info from SteamCMD
|
|
if [ -f "${HOME}/Steam/appcache/appinfo.vdf" ]; then
|
|
rm -f "${HOME}/Steam/appcache/appinfo.vdf"
|
|
fi
|
|
# check for new build
|
|
availablebuild=$(${STEAMCMD} +login "${steamlogin}" +app_info_update 1 +app_info_print "${appid}" +app_info_print \
|
|
"${appid}" +quit | sed -n '/branch/,$p' | grep -m 1 buildid | tr -cd '[:digit:]')
|
|
if [ -z "${availablebuild}" ]; then
|
|
printf "\r[ ${red}FAIL${default} ] Checking for update:\n"
|
|
printf "\r[ ${red}FAIL${default} ] Checking for update:: Not returning version info\n"
|
|
exit
|
|
else
|
|
printf "\r[ ${green}OK${default} ] Checking for update:"
|
|
fi
|
|
# compare builds
|
|
if [ "${currentbuild}" != "${availablebuild}" ]; then
|
|
printf "\r[ ${green}OK${default} ] Checking for update:: Update available\n"
|
|
printf "Update available:\n"
|
|
printf "\tCurrent build: ${red}${currentbuild}${default}\n"
|
|
printf "\tAvailable build: ${green}${availablebuild}${default}\n"
|
|
printf "\thttps://steamdb.info/app/${appid}/\n"
|
|
printf "\nApplying update"
|
|
# run update
|
|
fn_runupdate_dayz
|
|
fn_workshop_mods
|
|
else
|
|
printf "\r[ ${green}OK${default} ] Checking for update:: No update available\n"
|
|
printf "\nNo update available:\n"
|
|
printf "\tCurrent version: ${green}${currentbuild}${default}\n"
|
|
printf "\tAvailable version: ${green}${availablebuild}${default}\n"
|
|
printf "\thttps://steamdb.info/app/${appid}/\n\n"
|
|
fi
|
|
}
|
|
|
|
fn_workshop_mods(){
|
|
fn_steamlogin_dayz
|
|
declare -a workshopID
|
|
workshopfolder="${SERVER_FILES}/steamapps/workshop/content/${dayz_id}"
|
|
workshoplist=""
|
|
if [ ! -f "${WORKSHOP_CFG}" ]
|
|
then
|
|
echo "No workshop mods..."
|
|
return
|
|
else
|
|
echo "Syncing workshop mods..."
|
|
fi
|
|
mapfile -t workshopID < "${WORKSHOP_CFG}"
|
|
# gather mods
|
|
for i in "${workshopID[@]}"
|
|
do
|
|
if [[ $i =~ ^[0-9] ]] && [ $(expr length $i) -gt 7 ]; then
|
|
workshoplist+=" +workshop_download_item "${dayz_id}" "$i""
|
|
fi
|
|
done
|
|
# download mods
|
|
${STEAMCMD} +force_install_dir ${SERVER_FILES} +login "${steamlogin}" ${workshoplist} +quit
|
|
# link mods
|
|
for i in "${workshopID[@]}"
|
|
do
|
|
if [[ $i =~ ^[0-9] ]] && [ $(expr length $i) -gt 7 ] && [ -d "${workshopfolder}/$i" ]; then
|
|
modname=$(cut -d '"' -f 2 <<< $(grep name ${workshopfolder}/$i/meta.cpp))
|
|
if [ ! -d "${SERVER_FILES}/@${modname}" ]; then
|
|
ln -s ${workshopfolder}/$i "${SERVER_FILES}/@${modname}" &> /dev/null
|
|
fi
|
|
find "${workshopfolder}/$i" -depth -exec rename -f 's/(.*)\/([^\/]*)/$1\/\L$2/' {} \;
|
|
fi
|
|
done
|
|
if ls ${SERVER_FILES}/@* 1> /dev/null 2>&1; then
|
|
printf "\n[ ${green}DayZ${default} ] Copy Key Files from Mods...\n"
|
|
cp -vu ${SERVER_FILES}/@*/keys/* "${SERVER_FILES}/keys/" > /dev/null 2>&1
|
|
fi
|
|
}
|
|
|
|
fn_rcon(){
|
|
exec /usr/local/py3rcon/py3rcon.py --gui ~/py3rcon.config.json
|
|
}
|
|
|
|
fn_status(){
|
|
INSTALLED="${NO}"
|
|
LOGGED_IN="${NO}"
|
|
RUNNING="${NO}"
|
|
MOD_INSTALLED="${yellow}0${default}"
|
|
MOD_LIST=""
|
|
# DayZ Server files installation
|
|
if [ -f "${SERVER_INSTALL_FILE}" ]
|
|
then
|
|
INSTALLED="${YES}"
|
|
fi
|
|
# Logged into Steam
|
|
if [ -f "${STEAM_LOGIN}" ]
|
|
then
|
|
LOGGED_IN="${YES}"
|
|
if grep -q anonymous "${STEAM_LOGIN}"
|
|
then
|
|
ANONYMOUS="(as anonymous)"
|
|
fi
|
|
fi
|
|
# Running or not
|
|
if pidof DayZServer > /dev/null
|
|
then
|
|
RUNNING="${YES}"
|
|
fi
|
|
# Number of mods plus the list denoting on or off
|
|
echo -e "
|
|
Status:
|
|
|
|
Logged in to Steam: ${LOGGED_IN} ${ANONYMOUS}
|
|
Server files installed: ${INSTALLED}
|
|
Mods installed: ${MOD_INSTALLED}${MOD_LIST}
|
|
Server running: ${RUNNING}
|
|
"
|
|
}
|
|
|
|
case "${1}" in
|
|
install)
|
|
fn_loadconfig_dayz
|
|
fn_install_dayz
|
|
;;
|
|
login)
|
|
fn_loadconfig_dayz
|
|
fn_steam_login
|
|
;;
|
|
rcon)
|
|
fn_rcon "${2}"
|
|
;;
|
|
start)
|
|
fn_loadconfig_dayz
|
|
fn_start_dayz
|
|
;;
|
|
status)
|
|
fn_status
|
|
;;
|
|
stop)
|
|
fn_stop_dayz
|
|
;;
|
|
update)
|
|
fn_loadconfig_dayz
|
|
fn_update_dayz
|
|
;;
|
|
workshop)
|
|
fn_loadconfig_dayz
|
|
fn_workshop_mods "${2}"
|
|
;;
|
|
**)
|
|
fn_usage "$*"
|
|
;;
|
|
esac
|