dayzdockerserver/web/bin/dz
Daniel Ceregatti 2f1509fb65 Change the default maps to always come from github. One used to be able to install the server using the anonymous steam user, but now the mpmissions aren't included if the anonymous user is used.
Handle multiple env files for now while we transition server orchestration entirely to the web container.
Add MuchStuffPack mod integration.
Add git to the web container so we can checkout server resources from github as git. Allows us to just pull on git to keep up to date.
2024-06-19 16:59:33 -07:00

373 lines
9.8 KiB
Bash
Executable file

#!/usr/bin/env bash
source dz-common
# An array to store Workshop items. Each element contains the mod's ID, name, and state (active or not).
WORKSHOP_DIR="/mods/${release_client_appid}"
if [ ! -d ${WORKSHOP_DIR} ]
then
mkdir -p ${WORKSHOP_DIR}
fi
workshoplist=""
# Functions
# Usage
usage(){
echo -e "
${red}Bad option or arguments! ${yellow}${*}${default}
Usage: ${green}$(basename $0)${yellow} option [ arg1 [ arg2 ] ]
Options and arguments:
a|add id - Add a DayZ Workshop item by id. Added items become active by default
i|install - Install the DayZ server files
g|login - Login to Steam.
m|modupdate - Update the mod files
p|map id - Install a mod's mpmissions files by id. (Presumes template exists)
r|remove id - Remove all files and directories of a Workshop item by id
l|s|status - Shows Steam login status, if base files are installed, installed mods
u|update - Update the server files
x|xml id - Get and normalize XML files from a mod's template by id (Presumes template exists)
${default}"
exit 1
}
# Manage the mod symlink
symlink(){
W=${1}
ID=${2}
NAME=${3}
if [ ! -L "${SERVER_FILES}/@${NAME}" ] && [[ ${W} = 1 ]]
then
ln -sv ${WORKSHOP_DIR}/${ID} "${SERVER_FILES}/@${NAME}"
elif [[ "${W}" = "0" ]]
then
rm -vf "${SERVER_FILES}/@${NAME}"
fi
}
installxml(){
ID=${1}
# Going to have to maintain a matrix of file names -> root node -> child node permutations
for i in "CFGEVENTGROUPS:eventgroupdef:group" "CFGEVENTSPAWNS:eventposdef:event" "CFGSPAWNABLETYPES:spawnabletypes:type" "EVENTS:events:event" "TYPES:types:type"
do
var=$(echo ${i} | cut -d: -f1)
CHECK=$(echo ${i} | cut -d: -f2)
if [ -f "${WORKSHOP_DIR}/${ID}/${var,,}.xml" ]
then
echo "Normalizing ${WORKSHOP_DIR}/${ID}/${var,,}.xml..."
cp ${WORKSHOP_DIR}/${ID}/${var,,}.xml /tmp/x
# Quirks
# Some cfgeventspanws.xml files have <events> instead of <eventposdef>. Let's just try to fix that first.
if [[ ${var} = "CFGEVENTSPAWNS" ]]
then
if grep -q '<events>' /tmp/x
then
echo " - (Quirk) has <events> instead of <eventposdef>. fixing..."
xmlstarlet ed -L -r "events" -v "eventposdef" /tmp/x
fi
fi
if ! grep -q '<'${CHECK}'>' /tmp/x
then
echo " - has no root node <${CHECK}>. fixing..."
echo '<'${CHECK}'>' > /tmp/y
cat /tmp/x >> /tmp/y
echo '</'${CHECK}'>' >> /tmp/y
xmlstarlet fo /tmp/y > /tmp/x
fi
if ! grep -q '<?xml' /tmp/x
then
echo " - has no XML node, fixing..."
xmlstarlet fo /tmp/x > /tmp/y
mv /tmp/y /tmp/x
fi
xmllint --noout /tmp/x && (
# Keep the normalized version in the /mods directory
cp /tmp/x ${WORKSHOP_DIR}/${ID}/${var,,}.xml
echo -e "${green}${WORKSHOP_DIR}/${ID}/${var,,}.xml passes XML lint test!${default}"
) || (
echo -e "${yellow}The final ${WORKSHOP_DIR}/${ID}/${var,,}.xml does not pass XML lint test! IT WAS NOT COPIED!${default}"
)
fi
done
exit 0
}
# Add a mod
add(){
if [ -d "${WORKSHOP_DIR}/${1}" ]
then
echo -e "${yellow}Warning: The mod directory ${WORKSHOP_DIR}/${1} already exists!${default}"
MODNAME=$(get_mod_name ${1})
fi
if [ -L "${SERVER_FILES}/@${MODNAME}" ]
then
echo -e "${yellow}Warning: The mod symlink ${SERVER_FILES}/@${MODNAME} already exists!${default}"
fi
echo "Adding mod id ${1}"
dologin
${STEAMCMD} +force_install_dir ${SERVER_FILES} +login "${steamlogin}" +workshop_download_item "${release_client_appid}" "${1}" +quit
# Make sure the install succeeded
if [ ! -d "${WORKSHOP_DIR}/${1}" ]
then
echo -e "${red}Mod installation failed: The mod directory ${WORKSHOP_DIR}/${1} was not created!${default}"
echo "Installation failed! See above (You probably need to use a real Steam login)"
return
fi
# Get the name of the newly added mod
MODNAME=$(get_mod_name ${1})
symlink 1 ${1} "${MODNAME}"
echo -e "Mod id ${1} - ${green}${MODNAME}${default} - added"
xml ${ID}
}
# Remove a mod
remove(){
DIR="${WORKSHOP_DIR}/${1:?}"
if [ -d "${DIR}" ]
then
MODNAME=$(get_mod_name ${1})
echo "Removing directory ${DIR}"
rm -rf "${DIR}"
else
echo "Directory ${DIR} doesn't exist?"
fi
if [ -L "${SERVER_FILES}/@${MODNAME}" ]
then
echo "Removing symlink ${SERVER_FILES}/@${MODNAME}"
rm -f "${SERVER_FILES}/@${MODNAME}"
else
echo "Symlink ${SERVER_FILES}/@${MODNAME} doesn't exist?"
fi
echo -e "Mod id ${1} - ${red}${MODNAME}${default} - removed"
}
# Handle the Steam login information.
login(){
if [ -f "${STEAM_LOGIN}" ]
then
if 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
}
# "Perform" the Steam login. This just sources the file with the Steam login name.
dologin(){
if [ -f "${STEAM_LOGIN}" ]
then
source "${STEAM_LOGIN}"
else
echo "No cached Steam credentials. Please configure this now: "
login
fi
}
# Perform the installation of the server files.
install(){
if [ ! -f "${SERVER_INSTALL_FILE}" ] || [[ ${1} = "force" ]]
then
printf "[ ${yellow}DayZ${default} ] Downloading DayZ Server-Files!\n"
dologin
${STEAMCMD} +force_install_dir ${SERVER_FILES} +login "${steamlogin}" +app_update "${release_server_appid}" validate +quit
else
printf "[ ${lightblue}DayZ${default} ] The server is already installed.\n"
fi
}
# Update the server files.
update(){
dologin
appmanifestfile=${SERVER_FILES}/steamapps/appmanifest_"${release_server_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 "${release_server_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}" ] || [[ ${1} = "force" ]]
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/${release_server_appid}/\n"
printf "\nApplying update"
# run update
dologin
${STEAMCMD} +force_install_dir ${SERVER_FILES} +login "${steamlogin}" +app_update "${release_server_appid}" validate +quit
modupdate
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/${release_server_appid}/\n\n"
fi
}
# Update mods
modupdate(){
echo "Updating mods..."
dologin
get_mods
${STEAMCMD} +force_install_dir ${SERVER_FILES} +login "${steamlogin}" ${workshoplist} +quit
# Updated files come in with mixed cases. Fix that.
echo "done"
echo
}
# Display the status of everything
status(){
INSTALLED="${NO}"
LOGGED_IN="${NO}"
# DayZ Server files installation
if [ -f "${SERVER_INSTALL_FILE}" ]
then
INSTALLED="${YES}"
if [[ ${release_client_appid} = "221100" ]]
then
RELEASE="Stable"
else
RELEASE="Experimental"
fi
VERSION="$(strings /serverfiles/DayZServer | grep -P "DayZ \d\.\d+\.\d+" | cut -c6-) - ${RELEASE}"
fi
# Logged into Steam
if [ -f "${STEAM_LOGIN}" ]
then
LOGGED_IN="${YES}"
if grep -q anonymous "${STEAM_LOGIN}"
then
ANONYMOUS="${yellow}(as anonymous)${default}"
else
ANONYMOUS="${green}(not anonymous)${default}"
fi
fi
echo -ne "
Logged in to Steam: ${LOGGED_IN} ${ANONYMOUS}
Server files installed: ${INSTALLED}"
if [[ "${INSTALLED}" = "${NO}" ]]
then
echo
echo
exit 0
fi
# Version of DayZ Server files
echo -ne "
Version: ${VERSION}"
# Mods
echo -ne "
Mods: "
MODS=$(list)
if [[ ${MODS} == "" ]]
then
echo -ne "${red}none${default}"
fi
echo -e "${MODS}"
}
map(){
# Install map mpmissions for mods that have them. Presumes a map.env was created for the mod, with the required metadata (git URL, etc.)
TERM="map"
if [[ "${1}" =~ ^[0-9]+$ ]]
then
TERM="mod id"
fi
if [ -f "${FILES}/mods/${1}/map.env" ]
then
echo "Installing mpmissions files for ${TERM} ${1}..."
source ${FILES}/mods/${1}/map.env
${FILES}/bin/map.sh ${1} install
fi
}
mod_install(){
if [ -f ${FILES}/mods/${1}/${2}.sh ]
then
echo "An ${2}.sh was found for mod id ${1}. Running..."
${FILES}/mods/${1}/${2}.sh
fi
# A generic map install script. Presumes a git repo as the source
}
# "Manage" XML files.
xml(){
/files/bin/xml.sh ${1}
installxml ${1}
}
# Capture the first argument and shift it off so we can pass $@ to every function
C=${1}
shift || {
usage
}
case "${C}" in
a|add)
add "${@}"
;;
i|install)
install "${@}"
;;
g|login)
login "${@}"
;;
m|modupdate)
modupdate "${@}"
;;
r|remove)
remove "${@}"
;;
l|s|status)
status "${@}"
;;
p|map)
map "${@}"
;;
u|update)
update "${@}"
;;
x|xml)
xml "${@}"
;;
*)
usage "$*"
;;
esac