There are no mpmissions in the server container when it starts for the first time. Ensure Chernarus is copied over as a default when this is detected, as the server is expected to start successfully. Presumes a default config where the map hasn't been changed.

Make development work by setting an environment variable.
Set the web container to restart instead of not, should the express server crash.
Copy XML files that are merged when the server  starts only when the mpmissions directory exists.
Refactor XML functions for better naming.
Handle display of lists when no mods are installed.
Add support for adding mpmissions for Deer Isle and mpmissions in general via mod integrations.
Add support for Red Falcon Watercraft XML files. WIP.
Add a deer isle DayZ bicycle spawn file.
This commit is contained in:
Daniel Ceregatti 2023-09-07 12:08:12 -07:00
parent 5db38636c4
commit 887374587d
7 changed files with 102 additions and 75 deletions

View file

@ -32,7 +32,7 @@ services:
ports: ports:
- "8001:8001/tcp" - "8001:8001/tcp"
- "8000:8000/tcp" - "8000:8000/tcp"
restart: no restart: always
environment: environment:
# The use of the Steam API in the (very incomplete) web app requires a key. Get yours here: https://steamcommunity.com/dev/apikey # The use of the Steam API in the (very incomplete) web app requires a key. Get yours here: https://steamcommunity.com/dev/apikey
- STEAMAPIKEY=YOUR_STEAM_API_KEY_HERE - STEAMAPIKEY=YOUR_STEAM_API_KEY_HERE
@ -63,11 +63,15 @@ services:
# - 27016:27016/udp # - 27016:27016/udp
# Always restart, unless stopped # Always restart, unless stopped
restart: unless-stopped restart: unless-stopped
environment:
# To prevent the server from starting to allow for development, set this to 1
- DEVELOPMENT=0
# Allows attaching a debugger from the host # Allows attaching a debugger from the host
cap_add: # cap_add:
- SYS_PTRACE # - SYS_PTRACE
# Allows core files to be created within the container. These are VERY LARGE! Enable only for debugging! # Allows core files to be created within the container. These are VERY LARGE! Enable only for debugging!
ulimits: # One must also set the sysctl kernel.core_pattern parameter ON THE HOST to a path that is writable within the container. YMMV
core: # ulimits:
soft: -1 # core:
hard: -1 # soft: -1
# hard: -1

View file

@ -67,15 +67,20 @@ prompt_yn(){
# List mods # List mods
list(){ list(){
X=1 X=1
C="${green}" C="${green}"
spaces=" " spaces=" "
echo FIRST=1
echo -e " ID Name URL Size" for link in $(ls -d ${SERVER_FILES}/@* 2> /dev/null | sort)
echo "------------------------------------------------------------------------------------------------------------------------" do
for link in $(ls -d ${SERVER_FILES}/@* | sort) if [[ ${FIRST} = 1 ]]
do then
echo
echo -e " ID Name URL Size"
echo "------------------------------------------------------------------------------------------------------------------------"
FIRST=0
fi
ID=$(readlink ${link} | awk -F/ '{print $NF}') ID=$(readlink ${link} | awk -F/ '{print $NF}')
MODNAME=$(get_mod_name ${ID}) MODNAME=$(get_mod_name ${ID})
SIZE=$(du -sh "${WORKSHOP_DIR}/${ID}" | awk '{print $1}') SIZE=$(du -sh "${WORKSHOP_DIR}/${ID}" | awk '{print $1}')
printf "${C}%.3d %s %.30s %s https://steamcommunity.com/sharedfiles/filedetails/?id=%s %s${default}\n" ${X} ${ID} "${MODNAME}" "${spaces:${#MODNAME}+1}" ${ID} ${SIZE} printf "${C}%.3d %s %.30s %s https://steamcommunity.com/sharedfiles/filedetails/?id=%s %s${default}\n" ${X} ${ID} "${MODNAME}" "${spaces:${#MODNAME}+1}" ${ID} ${SIZE}
X=$((X+1)) X=$((X+1))
@ -102,19 +107,19 @@ get_mod_id(){
echo -n ${1} echo -n ${1}
return return
fi fi
# If we have a second argument, we want to iterate over active server mods # If we have a second argument, we want to iterate over active server mods
DIR=${SERVER_FILES} DIR=${SERVER_FILES}
ARG="-d" ARG="-d"
if [[ ${2} = "0" ]] if [[ ${2} = "0" ]]
then then
ARG="-tdr" ARG="-tdr"
DIR=${SERVER_PROFILE} DIR=${SERVER_PROFILE}
fi fi
# echo "DIR: ${DIR}, ARG: ${ARG}" >&2 # echo "DIR: ${DIR}, ARG: ${ARG}" >&2
X=1 X=1
# Loop over mods # Loop over mods
for link in $(ls ${ARG} ${DIR}/@* 2> /dev/null) for link in $(ls ${ARG} ${DIR}/@* 2> /dev/null)
do do
ID=$(readlink ${link} | awk -F/ '{print $NF}') ID=$(readlink ${link} | awk -F/ '{print $NF}')
if [[ ${X} = ${1} ]] if [[ ${X} = ${1} ]]
then then
@ -127,27 +132,27 @@ get_mod_id(){
get_mods(){ get_mods(){
workshoplist="" workshoplist=""
for link in $(ls -d ${SERVER_FILES}/@* 2> /dev/null | sort) for link in $(ls -d ${SERVER_FILES}/@* 2> /dev/null | sort)
do do
ID=$(readlink ${link} | awk -F/ '{print $NF}') ID=$(readlink ${link} | awk -F/ '{print $NF}')
MODNAME=$(get_mod_name ${ID}) MODNAME=$(get_mod_name ${ID})
workshoplist+=" +workshop_download_item "${release_client_appid}" "${ID} workshoplist+=" +workshop_download_item "${release_client_appid}" "${ID}
done done
get_mod_command_line get_mod_command_line
} }
get_mod_command_line(){ get_mod_command_line(){
mod_command_line="" mod_command_line=""
for link in $(ls -tdr ${SERVER_PROFILE}/@* 2> /dev/null) for link in $(ls -tdr ${SERVER_PROFILE}/@* 2> /dev/null)
do do
ID=$(readlink ${link} | awk -F/ '{print $NF}') ID=$(readlink ${link} | awk -F/ '{print $NF}')
MODNAME=$(get_mod_name ${ID}) MODNAME=$(get_mod_name ${ID})
mod_command_line+="@${MODNAME};" mod_command_line+="@${MODNAME};"
done done
if [[ ${mod_command_line} != "" ]] if [[ ${mod_command_line} != "" ]]
then then
mod_command_line='-mod='${mod_command_line::-1} mod_command_line='-mod='${mod_command_line::-1}
fi fi
} }
# Copy mod keys # Copy mod keys

View file

@ -2,27 +2,27 @@
set -eE set -eE
source /files/mods/${1}/install.env if [ -f /files/mods/${1}/install.env ]
then
source /files/mods/${1}/install.env
else
echo "install.env not found for mod id ${1}..."
exit 1
fi
echo
if [[ ${2} = "uninstall" ]] if [[ ${2} = "uninstall" ]]
then then
echo "Backing up, as uninstalling will remove the ${MAP} mpmissions directory" echo "Backing up, as uninstalling will remove the ${MAP} mpmissions directory"
dayzserver backup dz backup
echo "Uninstalling mpmissions..."
echo
rm -rf ${SERVER_FILES}/mpmissions/${MPDIR} rm -rf ${SERVER_FILES}/mpmissions/${MPDIR}
elif [[ ${2} = "update" ]] elif [[ ${2} = "update" ]]
then then
echo "Updating mpmissions directory..."
echo
cd /tmp cd /tmp
git clone ${REPO} 2> /dev/null 1> /dev/null git clone ${REPO} 2> /dev/null 1> /dev/null
cp -a ${DIR}/${MPDIR} ${SERVER_FILES}/mpmissions cp -a ${DIR}/${MPDIR} ${SERVER_FILES}/mpmissions
rm -rf ${DIR} rm -rf ${DIR}
else elif [[ ${2} = "install" ]]
echo "Installing mpmissions files..." then
echo
cd /tmp cd /tmp
git clone ${REPO} 2> /dev/null 1> /dev/null git clone ${REPO} 2> /dev/null 1> /dev/null
cp -a ${DIR}/${MPDIR} ${SERVER_FILES}/mpmissions cp -a ${DIR}/${MPDIR} ${SERVER_FILES}/mpmissions

View file

@ -7,6 +7,11 @@ set -eE
ID=${1} ID=${1}
if ! [ -f ${FILES}/mods/${ID}/xml.env ]
then
exit 0
fi
source ${FILES}/mods/${ID}/xml.env source ${FILES}/mods/${ID}/xml.env
# Iterate over the file names we can handle # Iterate over the file names we can handle

View file

@ -126,15 +126,21 @@ report() {
mergexml(){ mergexml(){
# First copy the pristine files from upstream # First copy the pristine files from upstream
echo "Copying pristine versions of cfgeconomycore.xml and cfgeventspawns.xml..." for i in cfgeconomycore.xml #cfgeventspawns.xml
find /mpmissions -name cfgeconomycore.xml -exec cp -v {} ${SERVER_FILES}{} \; do
# find /mpmissions -name cfgeventspawns.xml -exec cp {} ${SERVER_FILES}{} \; echo "Copying pristine version of ${i} into local mpmission(s)..."
for dir in $(ls -d ${MPMISSIONS}/*)
do
#echo "dir: ${dir}, basename: $(basename ${dir})"
find /mpmissions/$(basename ${dir}) -name ${i} -exec cp -v {} ${SERVER_FILES}{} \;
done
done
# Follow https://community.bistudio.com/wiki/DayZ:Central_Economy_mission_files_modding and make a single XML # Follow https://community.bistudio.com/wiki/DayZ:Central_Economy_mission_files_modding and make a single XML
# file for the ones that can go into it. # file for the ones that can go into it.
for link in $(ls -tdr ${SERVER_PROFILE}/@* 2> /dev/null) for link in $(ls -tdr ${SERVER_PROFILE}/@* 2> /dev/null)
do do
ID=$(readlink ${link} | awk -F/ '{print $NF}') ID=$(readlink ${link} | awk -F/ '{print $NF}')
# Going to have to maintain a matrix of file names -> root node -> child node permutations # Going to have to maintain a matrix of file names -> root node -> child node permutations
C="" C=""
for i in "CFGSPAWNABLETYPES:spawnabletypes:type" "EVENTS:events:event" "TYPES:types:type" for i in "CFGSPAWNABLETYPES:spawnabletypes:type" "EVENTS:events:event" "TYPES:types:type"
@ -180,13 +186,20 @@ mergexml(){
# Start the server in the foreground # Start the server in the foreground
start(){ start(){
# Ensure mpmissions has at least one map. If not, block the server from starting # Ensure mpmissions has at least one map. If not, copy it from the local read-only volume that stores pristine mpmissons directories
if [ ! -d "${MPMISSIONS}/dayzOffline.chernarusplus" ] if [ ! -d "${MPMISSIONS}/dayzOffline.chernarusplus" ]
then then
echo echo
echo "Performing one-time copy of Chernarus mpmissions..." echo "Performing one-time copy of Chernarus mpmissions..."
echo echo
cp -a /mpmission/dayzOffline.chernarusplus ${MPMISSIONS} cp -av /mpmissions/dayzOffline.chernarusplus ${MPMISSIONS}
fi
# If we're developing, just block the container
if [[ ${DEVELOPMENT} = "1" ]]
then
echo "DEVELOPMENT mode, blocking..."
tail -f /dev/null
exit 0
fi fi
# Do the report on exit. Set here so that it only happens once we're starting the server, and not for other actions. # Do the report on exit. Set here so that it only happens once we're starting the server, and not for other actions.
trap ' trap '
@ -422,9 +435,6 @@ case "${C}" in
n|rcon) n|rcon)
rcon "${@}" rcon "${@}"
;; ;;
r|remove)
remove "${@}"
;;
r|restart) r|restart)
restart "${@}" restart "${@}"
;; ;;

View file

@ -1,14 +1,11 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Set PS1 so we know we're in the container # Set PS1 so we know we're in the container, should we exec into it.
cat > .bashrc <<EOF cat > .bashrc <<EOF
alias ls='ls --color' alias ls='ls --color'
export PS1="${debian_chroot:+($debian_chroot)}\u@dz-server:\w\$ " export PS1="${debian_chroot:+($debian_chroot)}\u@dz-server:\w\$ "
EOF EOF
# Uncomment the line below to run things manually in the container, then run: # Start the server.
# docker compose exec main bash, and from within the container: dz start (or do whatever) # If the DEVELOPMENT environment variable is set to 1, the container will just block and not start the server.
#tail -f /dev/null
# Otherwise, start the server normally
dz start dz start

View file

@ -26,6 +26,7 @@ Options and arguments:
i|install - Install the DayZ server files i|install - Install the DayZ server files
g|login - Login to Steam. g|login - Login to Steam.
m|modupdate - Update the mod files 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 r|remove id - Remove all files and directories of a Workshop item by id
s|status - Shows Steam login status, if base files are installed, installed mods s|status - Shows Steam login status, if base files are installed, installed mods
u|update - Update the server files u|update - Update the server files
@ -110,7 +111,7 @@ add(){
# Lower case all the files in mod directories. # Lower case all the files in mod directories.
find "${WORKSHOP_DIR}/${1}" -depth -exec rename -f 's/(.*)\/([^\/]*)/$1\/\L$2/' {} \; find "${WORKSHOP_DIR}/${1}" -depth -exec rename -f 's/(.*)\/([^\/]*)/$1\/\L$2/' {} \;
echo -e "Mod id ${1} - ${green}${MODNAME}${default} - added" echo -e "Mod id ${1} - ${green}${MODNAME}${default} - added"
installxml ${ID} xml ${ID}
} }
# Remove a mod # Remove a mod
@ -241,7 +242,6 @@ modupdate(){
status(){ status(){
INSTALLED="${NO}" INSTALLED="${NO}"
LOGGED_IN="${NO}" LOGGED_IN="${NO}"
RUNNING="${NO}"
# DayZ Server files installation # DayZ Server files installation
if [ -f "${SERVER_INSTALL_FILE}" ] if [ -f "${SERVER_INSTALL_FILE}" ]
@ -274,31 +274,34 @@ Mods: "
MODS=$(list) MODS=$(list)
if [[ ${MODS} == "" ]] if [[ ${MODS} == "" ]]
then then
echo -n "none" echo -ne "${red}none${default}"
fi fi
echo -e "${MODS}" echo -e "${MODS}"
} }
check_mod_install(){ map(){
# See if this mod id exists in files/mods, and offer to install other server side files if an install.sh is found # Install map mpmissions for mods that have them. Presumes a map.env was created for the mod, with the required metadata (git URL, etc.)
if [ -f ${FILES}/mods/${1}/install.env ]
then
echo "Installing mpmissions files for mod id ${1}..."
source ${FILES}/mods/${1}/install.env
${FILES}/bin/install.sh ${1} install
fi
}
mod_install(){
if [ -f ${FILES}/mods/${1}/${2}.sh ] if [ -f ${FILES}/mods/${1}/${2}.sh ]
then then
echo "An ${2}.sh was found for mod id ${1}. Running..." echo "An ${2}.sh was found for mod id ${1}. Running..."
${FILES}/mods/${1}/${2}.sh ${FILES}/mods/${1}/${2}.sh
fi fi
# A generic map install script. Presumes a git repo as the source # A generic map install script. Presumes a git repo as the source
if [ -f ${FILES}/mods/${1}/install.env ]
then
echo "An ${2}.env was found for mod id ${1}. Performing ${2}..."
source ${FILES}/mods/${1}/install.env
${FILES}/mods/install.sh ${1} ${2}
fi
} }
# "Manage" XML files. # "Manage" XML files.
xml(){ xml(){
/files/bin/xml.sh ${1} /files/bin/xml.sh ${1}
installxml ${1} #installxml ${1}
} }
# Capture the first argument and shift it off so we can pass $@ to every function # Capture the first argument and shift it off so we can pass $@ to every function
@ -326,6 +329,9 @@ case "${C}" in
l|s|status) l|s|status)
status "${@}" status "${@}"
;; ;;
p|map)
map "${@}"
;;
u|update) u|update)
update "${@}" update "${@}"
;; ;;