From 3fec572aa9844a90b06dd38f6d05d18b7ff61a43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20L=C3=B6sche?= Date: Fri, 2 Apr 2021 18:24:18 +0200 Subject: [PATCH] Initial BepInExPack mod support (Implements #282) (#288) * Initial BepInExPack mod support (Fixes #282) * Add BEPINEX info to README * Refactored vpenvconf to work for generic BepInEx config files and support special characters in variable names * Renamed vpenvconf -> env2cfg * Unify ValheimPlus and BepInExPack mod install and update code --- Dockerfile | 13 +- README.md | 100 ++++++-- bepinex-updater | 37 +++ common | 232 +++++++++++++++++- defaults | 11 +- env2cfg/README.md | 15 ++ .../vpenvconf => env2cfg/env2cfg}/__init__.py | 56 +++-- .../vpenvconf => env2cfg/env2cfg}/__main__.py | 2 +- {vpenvconf => env2cfg}/setup.cfg | 0 {vpenvconf => env2cfg}/setup.py | 8 +- .../test/test_env2cfg.py | 16 +- {vpenvconf => env2cfg}/tox.ini | 4 +- valheim-bootstrap | 28 ++- valheim-plus-updater | 132 +--------- valheim-server | 21 +- valheim-updater | 56 +++-- vpenvconf/README.md | 15 -- 17 files changed, 527 insertions(+), 219 deletions(-) create mode 100755 bepinex-updater create mode 100644 env2cfg/README.md rename {vpenvconf/vpenvconf => env2cfg/env2cfg}/__init__.py (61%) rename {vpenvconf/vpenvconf => env2cfg/env2cfg}/__main__.py (90%) rename {vpenvconf => env2cfg}/setup.cfg (100%) rename {vpenvconf => env2cfg}/setup.py (85%) rename vpenvconf/test/test_vpenvconf.py => env2cfg/test/test_env2cfg.py (72%) rename {vpenvconf => env2cfg}/tox.ini (89%) delete mode 100644 vpenvconf/README.md diff --git a/Dockerfile b/Dockerfile index 4d7e1ba..5ccc209 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,8 +17,8 @@ RUN curl -L -o /tmp/busybox.tar.bz2 https://busybox.net/downloads/busybox-${BUSY && make \ && cp busybox /usr/local/bin/ -WORKDIR /build/vpenvconf -COPY ./vpenvconf/ /build/vpenvconf/ +WORKDIR /build/env2cfg +COPY ./env2cfg/ /build/env2cfg/ RUN if [ "${TESTS:-true}" = true ]; then \ pip3 install tox \ && tox \ @@ -48,6 +48,7 @@ COPY valheim-bootstrap /usr/local/bin/ COPY valheim-backup /usr/local/bin/ COPY valheim-updater /usr/local/bin/ COPY valheim-plus-updater /usr/local/bin/ +COPY bepinex-updater /usr/local/bin/ COPY valheim-server /usr/local/bin/ COPY defaults /usr/local/etc/valheim/ COPY common /usr/local/etc/valheim/ @@ -62,18 +63,18 @@ RUN if [ "${TESTS:-true}" = true ]; then \ /usr/local/bin/valheim-server \ /usr/local/bin/valheim-updater \ /usr/local/bin/valheim-plus-updater \ + /usr/local/bin/bepinex-updater \ /usr/local/share/valheim/contrib/*.sh \ ; \ fi WORKDIR / RUN rm -rf /usr/local/lib/ RUN tar xzvf /build/supervisor/dist/supervisor-*.linux-x86_64.tar.gz -RUN tar xzvf /build/vpenvconf/dist/vpenvconf-*.linux-x86_64.tar.gz +RUN tar xzvf /build/env2cfg/dist/env2cfg-*.linux-x86_64.tar.gz RUN tar xzvf /build/python-a2s/dist/python-a2s-*.linux-x86_64.tar.gz COPY supervisord.conf /usr/local/etc/supervisord.conf RUN mkdir -p /usr/local/etc/supervisor/conf.d/ \ && chmod 600 /usr/local/etc/supervisord.conf - RUN echo "${SOURCE_COMMIT:-unknown}" > /usr/local/etc/git-commit.HEAD @@ -140,6 +141,7 @@ RUN dpkg --add-architecture i386 \ && ln -s /usr/local/bin/busybox /usr/local/bin/xz \ && ln -s /usr/local/bin/busybox /usr/local/bin/pstree \ && ln -s /usr/local/bin/busybox /usr/local/bin/killall \ + && ln -s /usr/local/bin/busybox /usr/local/bin/bc \ && curl -L -o /tmp/steamcmd_linux.tar.gz https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz \ && tar xzvf /tmp/steamcmd_linux.tar.gz -C /opt/steamcmd/ \ && chown -R root:root /opt/steamcmd \ @@ -149,7 +151,8 @@ RUN dpkg --add-architecture i386 \ /usr/bin/supervisord \ && cd "/opt/steamcmd" \ && ./steamcmd.sh +login anonymous +quit \ - && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \ + && date --utc --iso-8601=seconds > /usr/local/etc/build.date EXPOSE 2456-2457/udp EXPOSE 9001/tcp diff --git a/README.md b/README.md index a9d2542..c348bd2 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Valheim Server in a Docker Container (with [ValheimPlus](#valheimplus) support) * [Install extra packages](#install-extra-packages) * [Copy backups to another location](#copy-backups-to-another-location) * [Notify on Discord](#notify-on-discord) - * [ValheimPlus config from Environment Variables](#valheimplus-config-from-environment-variables) + * [Mod config from Environment Variables](#mod-config-from-environment-variables) * [System requirements](#system-requirements) * [Deployment](#deployment) * [Deploying with Docker and systemd](#deploying-with-docker-and-systemd) @@ -39,11 +39,14 @@ Valheim Server in a Docker Container (with [ValheimPlus](#valheimplus) support) * [Supervisor](#supervisor) * [Supervisor API](#supervisor-api) * [Status web server](#status-web-server) -* [ValheimPlus](#valheimplus) - * [Updates](#updates-1) - * [Configuration](#configuration) - * [Server data rate](#server-data-rate) - * [Disable server password](#disable-server-password) +* [Modding](#modding) + * [BepInExPack Valheim](#bepinexpack-valheim) + * [Configuration](#configuration) + * [ValheimPlus](#valheimplus) + * [Updates](#updates-1) + * [Configuration](#configuration-1) + * [Server data rate](#server-data-rate) + * [Disable server password](#disable-server-password) * [Changing startup CMD in Portainer](#changing-startup-cmd-in-portainer) * [Synology Help](#synology-help) * [First install](#first-install) @@ -104,6 +107,7 @@ Without it you will see a message `Warning: failed to set thread priority` in th # Environment Variables +**All variable names and values are case-sensitive!** | Name | Default | Purpose | |----------|----------|-------| | `SERVER_NAME` | `My Server` | Name that will be shown in the server browser | @@ -125,7 +129,8 @@ Without it you will see a message `Warning: failed to set thread priority` in th | `BACKUPS_MAX_AGE` | `3` | Age in days after which old backups are flushed | | `PERMISSIONS_UMASK` | `022` | [Umask](https://en.wikipedia.org/wiki/Umask) to use for backups, config files and directories | | `STEAMCMD_ARGS` | `validate` | Additional steamcmd CLI arguments | -| `VALHEIM_PLUS` | `false` | Whether [ValheimPlus](https://github.com/valheimPlus/ValheimPlus) mod should be loaded (config in `/config/valheimplus`) | +| `VALHEIM_PLUS` | `false` | Whether [ValheimPlus](https://github.com/valheimPlus/ValheimPlus) mod should be loaded (config in `/config/valheimplus`). Can not be used together with `BEPINEX`. | +| `BEPINEX` | `false` | Whether [BepInExPack Valheim](https://valheim.thunderstore.io/package/denikson/BepInExPack_Valheim/) mod should be loaded (config in `/config/bepinex`, plugins in `/opt/valheim/bepinex/BepInEx/plugins`). Can not be used together with `VALHEIM_PLUS`. | | `SUPERVISOR_HTTP` | `false` | Turn on supervisor's http server | | `SUPERVISOR_HTTP_PORT` | `9001` | Set supervisor's http server port | | `SUPERVISOR_HTTP_USER` | `admin` | Supervisor http server username | @@ -140,6 +145,7 @@ Without it you will see a message `Warning: failed to set thread priority` in th There are a few undocumented environment variables that could break things if configured wrong. They can be found in [`defaults`](defaults). + ## Log filters Valheim server by default logs a lot of noise. These env variables allow users to remove unwanted lines from the log. @@ -217,6 +223,9 @@ The following environment variables can be populated to run commands whenever sp | `POST_SERVER_RUN_HOOK` | | Command to be executed after the server has finished running. Server shutdown is blocked until this command returns or a shutdown timeout is triggered after 29 seconds. | | `PRE_SERVER_SHUTDOWN_HOOK` | | Command to be executed before the server is shut down. Server shutdown is blocked until this command returns. If `PRE_SERVER_SHUTDOWN_HOOK` holds the shutdown process for more than 90 seconds, the entire process will be hard-killed by `supervisord`. | | `POST_SERVER_SHUTDOWN_HOOK` | | Command to be executed after the server has finished shutting down. | +| `PRE_BEPINEX_CONFIG_HOOK` | | Command to be executed before writing BepInEx.cfg. | +| `POST_BEPINEX_CONFIG_HOOK` | | Command to be executed after writing BepInEx.cfg. Can be used to write your own mod config using [`env2cfg`](#mod-config-from-environment-variables). | + ### Event hook examples #### Install extra packages @@ -272,22 +281,51 @@ PRE_RESTART_HOOK=curl -sfSL -X PUT -d "{\"msgtype\":\"m.notice\",\"body\":\"Valh Note the `$(date +%s-%N)` is used for the required unique txnId. -## ValheimPlus config from Environment Variables -ValheimPlus config can be specified in environment variables using the syntax `VPCFG_
_=`. +## Mod config from Environment Variables +Mod config can be specified in environment variables using the syntax `_
_=`. + +**Predefined prefix list** +| Prefix | Mod | File | +|----------|----------|----------| +| `VPCFG` | ValheimPlus | `/config/valheimplus/valheim_plus.cfg` | +| `BEPINEXCFG` | BepInEx | `/config/valheimplus/BepInEx.cfg` or `/config/bepinex/BepInEx.cfg` depending on whether `VALHEIM_PLUS=true` or `BEPINEX=true` | + + +**Translation table** +Some characters that are allowed as section names in the config files are not allowed as environment variable names. They can be encoded using the following translation table. +| Variable name string | Replacement | +|----------|----------| +| `_DOT_` | `.` | +| `_HYPHEN_` | `-` | +| `_UNDERSCORE_` | `_` | +| `_PLUS_` | `+` | Example: ``` --e VPCFG_Server_enabled=true -e VPCFG_Server_enforceMod=false -e VPCFG_Server_dataRate=500 +-e VALHEIM_PLUS=true \ +-e VPCFG_Server_enabled=true \ +-e VPCFG_Server_enforceMod=false \ +-e VPCFG_Server_dataRate=500 \ +-e BEPINEXCFG_Logging_DOT_Console_Enabled=true ``` -turns into +turns into `/config/valheimplus/valheim_plus.cfg` ``` [Server] enabled=true enforceMod=false dataRate=500 ``` -All existing configuration in `/config/valheimplus/valheim_plus.cfg` is retained and a backup of the old config is created as `/config/valheimplus/valheim_plus.cfg.old` before writing the new config file. + +and `/config/valheimplus/BepInEx.cfg` +``` +[Logging.Console] +Enabled=true +``` + +All existing configuration in those files is retained and a backup of the old config is created as e.g. `/config/valheimplus/valheim_plus.cfg.old` before writing the new config file. + +You could generate your own custom plugin config from environment variables using [the `POST_BEPINEX_CONFIG_HOOK` event hook](#event-hooks) and [`env2cfg`](https://github.com/lloesche/valheim-server-docker/tree/main/env2cfg). # System requirements @@ -539,24 +577,46 @@ Within the container `status.json` is written to `STATUS_HTTP_HTDOCS` which by d As mentioned all the information is publicly available on the Valheim server query port. However the option is there to configure a `STATUS_HTTP_CONF` (`/config/httpd.conf` by default) containing [busybox httpd config](https://git.busybox.net/busybox/tree/networking/httpd.c) to limit access to the status web server by IP/subnet or login/password. +# Modding +## BepInExPack Valheim +**Enable with** +| Variable | Value | +|----------|----------| +| `BEPINEX` | `true` | + +[BepInExPack Valheim](https://valheim.thunderstore.io/package/denikson/BepInExPack_Valheim/) packages [BepInEx](https://github.com/BepInEx/BepInEx) for Valheim. BepInEx is a plugin / modding framework for Unity Mono, IL2CPP and .NET framework games. +To enable BepInExPack provide the env variable `BEPINEX=true`. This can not be specified together with `VALHEIM_PLUS=true`. +Just like Valheim Server this mod is automatically updated using the `UPDATE_CRON` schedule. + +Upon first start BepInExPack will create a new directory `/config/bepinex` where its config files are located. +BepInEx plugins must be copied into the `/config/bepinex/plugins/` directory. From there they will be automatically copied into `/opt/valheim/bepinex/BepInEx/plugins/` on install/update. + +### Configuration +See [Mod config from Environment Variables](#mod-config-from-environment-variables) + + +## ValheimPlus +**Enable with** +| Variable | Value | +|----------|----------| +| `VALHEIM_PLUS` | `true` | -# ValheimPlus -[ValheimPlus](https://github.com/valheimPlus/ValheimPlus) is a popular Valheim mod. -It has been incorporated into this container. To enable V+ provide the env variable `VALHEIM_PLUS=true`. +[ValheimPlus](https://github.com/valheimPlus/ValheimPlus) is a popular Valheim mod based on BepInEx. +It has been incorporated into this container. To enable V+ provide the env variable `VALHEIM_PLUS=true`. This can not be specified together with `BEPINEX=true`. Upon first start V+ will create a new directory `/config/valheimplus` where its config files are located. As a user you are mainly concerned with the values in `/config/valheimplus/valheim_plus.cfg`. For most modifications the mod has to be installed both, on the server as well as all the clients that connect to the server. A few modifications, like for example changing the `dataRate` can be done server only. -## Updates +### Updates ValheimPlus is automatically being updated using the same `UPDATE_CRON` schedule the Valheim server uses to check for updates. If an update of either Valheim server or ValheimPlus is found it is being downloaded, configured and the server automatically restarted. This also means your clients always need to run the latest ValheimPlus version or will not be able to connect. If this is undesired the schedule could be changed to only check for updates once per day. Example `UPDATE_CRON='0 6 * * *'` would only check at 6 AM. -## Configuration -See [ValheimPlus config from Environment Variables](#valheimplus-config-from-environment-variables) +### Configuration +See [Mod config from Environment Variables](#mod-config-from-environment-variables) -### Server data rate +#### Server data rate A popular change is to increase the server send rate. To do so enable ValheimPlus (`VALHEIM_PLUS=true`) and configure the following section in `/config/valheimplus/valheim_plus.cfg` @@ -570,7 +630,7 @@ dataRate=600 Alternatively start with `-e VPCFG_Server_enabled=true -e VPCFG_Server_enforceMod=false -e VPCFG_Server_dataRate=600`. -### Disable server password +#### Disable server password Another popular mod for LAN play that does not require the clients to run ValheimPlus is to turn off password authentication. To do so enable ValheimPlus (`VALHEIM_PLUS=true`), set an empty password (`SERVER_PASS=""`), make the server non-public (`SERVER_PUBLIC=false`) and configure the following section in `/config/valheimplus/valheim_plus.cfg` diff --git a/bepinex-updater b/bepinex-updater new file mode 100755 index 0000000..d25c55c --- /dev/null +++ b/bepinex-updater @@ -0,0 +1,37 @@ +#!/bin/bash +# bepinex-updater is being called by +# valheim-updater when $BEPINEX=true +# It downloads the BepInExPack mod and merges +# the downloaded archive with the vanilla +# Valheim server into /opt/valheim/bepinex + +# Include defaults and common functions +. /usr/local/etc/valheim/defaults +. /usr/local/etc/valheim/common + + +main() { + local api_response + local download_url + local remote_updated_at + + if ! api_response=$(curl -sfSL -H "accept: application/json" "https://valheim.thunderstore.io/api/experimental/package/denikson/BepInExPack_Valheim/"); then + fatal "Error: could not retrieve BepInEx release info from Thunderstore.io API" + fi + download_url=$(jq -r ".latest.download_url" <<< "$api_response" ) + remote_updated_at=$(jq -r ".date_updated" <<< "$api_response" ) + + check_for_mod_update \ + "$download_url" \ + "$remote_updated_at" \ + "$bepinex_zipfile" \ + "$bepinex_mergefile" \ + "$bepinex_download_path" \ + "$bepinex_config_path" \ + "extracted/BepInExPack_Valheim" \ + "$bepinex_install_path" \ + "BepInEx" +} + + +main diff --git a/common b/common index 26f6868..b0f315e 100644 --- a/common +++ b/common @@ -1,7 +1,9 @@ +#!/bin/bash # trap SIGUSR1 as it is being used to check # for process aliveness when an existing # pidfile is found trap ':' USR1 +just_started=${just_started:-true} # We are creating the following directory structure # /opt/valheim/ @@ -13,18 +15,31 @@ trap ':' USR1 # valheim_download_path=/opt/valheim/dl/server # Valheim server download directory valheim_install_path=/opt/valheim/server # Valheim server installation directory -vp_download_path=/opt/valheim/dl/plus # ValheimPlus download directory -vp_install_path=/opt/valheim/plus # ValheimPlus installation directory -vp_zipfile=UnixServer.zip # Name of the ValheimPlus archive valheim_restartfile="/tmp/valheim.restart" # Signaling file created by valheim-updater # or valheim-plus-updater that describes # if and how to restart the server + +# ValheimPlus Mod +vp_updater=/usr/local/bin/valheim-plus-updater +vp_download_path=/opt/valheim/dl/plus # ValheimPlus download directory +vp_install_path=/opt/valheim/plus # ValheimPlus installation directory +vp_zipfile=UnixServer.zip # Name of the ValheimPlus archive vp_mergefile="$vp_download_path/merge" # Signaling file created by valheim-updater # that tells valheim-plus-updater that Valheim # server was updated and needs to be merged # with ValheimPlus vp_config_path="/config/valheimplus" -just_started=${just_started:-true} + +# BepInEx Mod +bepinex_updater=/usr/local/bin/bepinex-updater +bepinex_download_path=/opt/valheim/dl/bepinex # BepInEx download directory +bepinex_install_path=/opt/valheim/bepinex # BepInEx installation directory +bepinex_config_path="/config/bepinex" +bepinex_mergefile="$bepinex_download_path/merge" # Signaling file created by valheim-updater + # that tells bepinex-updater that Valheim + # server was updated and needs to be merged + # with BepInEx +bepinex_zipfile=BepInEx.zip # Name of the BepInEx archive # Collection of PID files valheim_server_pidfile=/var/run/valheim-server.pid @@ -204,12 +219,45 @@ error_handler() { write_valheim_plus_config() { if [ -d "$vp_config_path" ]; then if env | grep "^$VALHEIM_PLUS_CFG_ENV_PREFIX" > /dev/null; then - /usr/local/bin/vpenvconf --verbose --config "$vp_config_path/valheim_plus.cfg" --env-prefix "$VALHEIM_PLUS_CFG_ENV_PREFIX" + /usr/local/bin/env2cfg --verbose --config "$vp_config_path/valheim_plus.cfg" --env-prefix "$VALHEIM_PLUS_CFG_ENV_PREFIX" fi fi } +write_bepinex_config() { + local config_path + if [ "$VALHEIM_PLUS" = true ]; then + config_path=$vp_config_path + plugins_path="$vp_install_path/BepInEx/plugins/" + elif [ "$BEPINEX" = true ]; then + config_path=$bepinex_config_path + plugins_path="$bepinex_install_path/BepInEx/plugins/" + else + error "Neither ValheimPlus nor BepInExPack enabled - not writing BepInEx config" + return 1 + fi + if [ -n "$PRE_BEPINEX_CONFIG_HOOK" ]; then + info "Running pre BepInEx config hook: $PRE_BEPINEX_CONFIG_HOOK" + eval "$PRE_BEPINEX_CONFIG_HOOK" + fi + if [ -d "$config_path" ]; then + if env | grep "^$BEPINEX_CFG_ENV_PREFIX" > /dev/null; then + /usr/local/bin/env2cfg --verbose --config "$config_path/BepInEx.cfg" --env-prefix "$BEPINEX_CFG_ENV_PREFIX" + fi + if [ -d "$config_path/plugins" ] && [ -d "$plugins_path" ]; then + mkdir -p "$plugins_path" + info "Copying BepInEx plugins from $config_path/plugins/ -> $plugins_path" + find "$config_path/plugins/" -type f -iname '*.dll' -print -exec cp -f "{}" "$plugins_path" \; + fi + fi + if [ -n "$POST_BEPINEX_CONFIG_HOOK" ]; then + info "Running post BepInEx config hook: $POST_BEPINEX_CONFIG_HOOK" + eval "$POST_BEPINEX_CONFIG_HOOK" + fi +} + + write_restart_file() { local mode local reason @@ -259,3 +307,177 @@ write_serverlist() { echo "$id_list" | sed -e "s/ \\+/\\n/g" >> "$list_file" fi } + + +extract_archive() { + local archive_path="$1" + local archive_file="$2" + cd "$archive_path" || fatal "Could not cd $archive_path" + debug "Extracting downloaded ZIP archive" + rm -rf extracted + mkdir -p extracted + unzip -d extracted/ "$archive_file" +} + + +download_mod() { + local download_url="$1" + local updated_at="$2" + local download_path="$3" + debug "Downloading $download_url to $download_path" + curl -sfSL -o "$download_path" "$download_url" \ + && echo "$updated_at" > "$download_path.updated_at" +} + + +check_merge() { + local mergefile=$1 + local download_path=$2 + local zipfile=$3 + local install_path=$4 + local config_path=$5 + local extraction_path=$6 + local mod_name=$7 + + # The control file $mergefile is either created + # in prepare_mod() if the mod is being installed for + # the first time or an update is available, or + # it is created by valheim-updater if a Valheim server update + # was downloaded and the mod needs to be applied to it. + if [ -f "$mergefile" ]; then + info "Valheim dedicated server or $mod_name got updated - extracting and merging installation files" + (set -e; extract_archive "$download_path" "$zipfile" && merge_mod "$install_path" "$config_path" "$download_path/$extraction_path") + # shellcheck disable=SC2181 + if [ $? -eq 0 ]; then + debug "Successfully installed $mod_name" + cp -f "$zipfile.updated_at" "$zipfile.installed_at" + rm -f "$mergefile" + else + error "Failed to extract and install $mod_name - retrying later" + fi + fi +} + + +prepare_mod() { + local download_url="$1" + local updated_at="$2" + local mergefile="$3" + local zipfile="$4" + download_mod "$download_url" "$updated_at" "$zipfile" \ + && touch "$mergefile" +} + + +merge_mod() { + local mod_install_path="$1" + local mod_config_path="$2" + local mod_download_path="$3" + local config_file + local pkg_config_dir + local dest_file + mod_config_path=${mod_config_path%/} + mod_download_path=${mod_download_path%/} + debug "Merging Valheim server and mod" + # remove any old install directories + rm -rf "$mod_install_path.tmp" "$mod_install_path.old" + # create a new install directory where we will stage the new version + mkdir -p "$mod_install_path.tmp" + # rsync all Valheim dedicated server files + rsync -a --itemize-changes --exclude server_exit.drp --exclude steamapps "$valheim_download_path/" "$mod_install_path.tmp" + # rsync all ValheimPlus mod files on top of the dedicated server files + rsync -a --itemize-changes "$mod_download_path/" "$mod_install_path.tmp" + # if /config/valheimplus/ does not exist copy the default config from the ZIP archive + mkdir -p "$mod_config_path/plugins" + pkg_config_dir="$mod_install_path.tmp/BepInEx/config" + if [ -d "$pkg_config_dir" ]; then + cd "$pkg_config_dir" || fatal "Could not cd $pkg_config_dir" + for config_file in *; do + dest_file="$mod_config_path/$config_file" + # always copy the configs that came with the latest ZIP archive to .cfg.default + cp -f "$config_file" "$dest_file.default" + if [ ! -f "$dest_file" ]; then + debug "Config $dest_file does not exist - copying from archive" + cp -f "$config_file" "$dest_file" + if [ "$config_file" = "valheim_plus.cfg" ]; then + write_valheim_plus_config + elif [ "$config_file" = "BepInEx.cfg" ]; then + write_bepinex_config + fi + fi + done + cd - || fatal "Could not cd -" + fi + # ensure config file permissions + ensure_permissions + # remove the config folder within the server directory and symlink it to /config + rm -rf "$pkg_config_dir" + ln -s "$mod_config_path" "$pkg_config_dir" + # move an existing copy of ValheimPlus to the .old extension + if [ -d "$mod_install_path" ]; then + mv -f "$mod_install_path" "$mod_install_path.old" + fi + # move the staging folder to the live folder and signal valheim-updater to restart the server + mv "$mod_install_path.tmp" "$mod_install_path" + write_restart_file updated +} + + +check_for_mod_update() { + local download_url="$1" + local remote_updated_at="$2" + local zipfile="$3" + local mergefile="$4" + local download_path="$5" + local config_path="$6" + local extraction_path="$7" + local install_path="$8" + local mod_name="$9" + local local_updated_at + local local_installed_at + + mkdir -p "$download_path" "$install_path" + cd "$download_path" || fatal "Could not cd $download_path" + if [ -f "$zipfile" ] && [ -f "$zipfile.updated_at" ] && [ -f "$zipfile.installed_at" ]; then + local_updated_at=$(< "$zipfile.updated_at") + local_installed_at=$(< "$zipfile.installed_at") + if [ "$local_updated_at" = "$remote_updated_at" ] && [ "$local_updated_at" = "$local_installed_at" ]; then + debug "Local $mod_name archive is identical to remote archive and was successfully installed - no update required" + else + info "Local $mod_name archive with update date $local_updated_at differs from date $remote_updated_at or failed to successfully install - updating" + prepare_mod "$download_url" "$remote_updated_at" "$mergefile" "$download_path/$zipfile" + fi + else + info "Fresh $mod_name install" + prepare_mod "$download_url" "$remote_updated_at" "$mergefile" "$download_path/$zipfile" + fi + + check_merge "$mergefile" "$download_path" "$zipfile" "$install_path" "$config_path" "$extraction_path" "$mod_name" +} + + +iec_size_format() { + local byte_size=$1 + local use_bc=false + local float_regex="^([0-9]+\\.?[0-9]*)\$" + + if [ -z "$byte_size" ] || ! [[ "$byte_size" =~ $float_regex ]]; then + error "Input $byte_size is no valid float" + return 1 + fi + if command -v bc > /dev/null 2>&1; then + use_bc=true + fi + for unit in B KiB MiB GiB TiB PiB EiB ZiB; do + if [ "${byte_size%.*}" -lt 1024 ]; then + printf "%.2f %s\\n" "$byte_size" "$unit" + return + fi + if [ "$use_bc" = true ]; then + byte_size=$(echo "$byte_size/1024" | bc -l) + else + byte_size=$((byte_size/1024)) + fi + done + printf "%.2f YiB\\n" $byte_size +} diff --git a/defaults b/defaults index 3d4e898..8a0e1a7 100644 --- a/defaults +++ b/defaults @@ -1,3 +1,4 @@ +#!/bin/bash # The following are default values. # They can be overridden by supplying the -e VAR=value option to the containerizer. @@ -22,6 +23,8 @@ STEAMCMD_ARGS=${STEAMCMD_ARGS-validate} DEBUG_START_FRESH=${DEBUG_START_FRESH:-false} # Flat to make valheim-plus-updater reinstall the V+ ZIP over vanilla server DEBUG_REINSTALL_VALHEIM_PLUS=${DEBUG_REINSTALL_VALHEIM_PLUS:-false} +# Flat to make bepinex-updater reinstall the BepInEx ZIP over vanilla server +DEBUG_REINSTALL_BEPINEX=${DEBUG_REINSTALL_BEPINEX:-false} # How often we check for Valheim server updates # This used to be 900 (15 min) and is here for backwards @@ -61,6 +64,8 @@ STATUS_HTTP_HTDOCS=${STATUS_HTTP_HTDOCS%/} # Mod support VALHEIM_PLUS=${VALHEIM_PLUS:-false} VALHEIM_PLUS_CFG_ENV_PREFIX=${VALHEIM_PLUS_CFG_ENV_PREFIX:-VPCFG_} +BEPINEX=${BEPINEX:-false} +BEPINEX_CFG_ENV_PREFIX=${BEPINEX_CFG_ENV_PREFIX:-BEPINEXCFG_} # Permissions PERMISSIONS_UMASK=${PERMISSIONS_UMASK:-022} @@ -85,8 +90,8 @@ export VALHEIM_LOG_FILTER_UTF8=${VALHEIM_LOG_FILTER_UTF8:-true} export VALHEIM_LOG_FILTER_MATCH=${VALHEIM_LOG_FILTER_MATCH- } export VALHEIM_LOG_FILTER_STARTSWITH=${VALHEIM_LOG_FILTER_STARTSWITH-(Filename:} export VALHEIM_LOG_FILTER_STARTSWITH_AssertionFailed=${VALHEIM_LOG_FILTER_STARTSWITH_AssertionFailed-src/steamnetworkingsockets/clientlib/steamnetworkingsockets_lowlevel.cpp} -if [ "$VALHEIM_PLUS" = true ]; then - export VALHEIM_LOG_FILTER_STARTSWITH_VP=${VALHEIM_LOG_FILTER_STARTSWITH_VP-Fallback handler could not load library} +if [ "$VALHEIM_PLUS" = true ] || [ "$BEPINEX" = true ]; then + export VALHEIM_LOG_FILTER_STARTSWITH_BepInEx=${VALHEIM_LOG_FILTER_STARTSWITH_BepInEx-Fallback handler could not load library} fi # Syslog settings @@ -115,6 +120,8 @@ PRE_SERVER_RUN_HOOK=${PRE_SERVER_RUN_HOOK:-} POST_SERVER_RUN_HOOK=${POST_SERVER_RUN_HOOK:-} PRE_SERVER_SHUTDOWN_HOOK=${PRE_SERVER_SHUTDOWN_HOOK:-} POST_SERVER_SHUTDOWN_HOOK=${POST_SERVER_SHUTDOWN_HOOK:-} +PRE_BEPINEX_CONFIG_HOOK=${PRE_BEPINEX_CONFIG_HOOK:-} +POST_BEPINEX_CONFIG_HOOK=${POST_BEPINEX_CONFIG_HOOK:-} # Adminlist/Bannedlist IDs ADMINLIST_IDS=${ADMINLIST_IDS:-} diff --git a/env2cfg/README.md b/env2cfg/README.md new file mode 100644 index 0000000..b36f874 --- /dev/null +++ b/env2cfg/README.md @@ -0,0 +1,15 @@ +# env2cfg +Generate mod configuration from env + +``` +usage: env2cfg [-h] [--verbose] [--config CONFIG_FILE] [--env-prefix ENV_PREFIX] + +Generate mod config from env + +optional arguments: + -h, --help show this help message and exit + --verbose, -v Verbose logging + --config CONFIG_FILE Path to mod config file (default: /config/bepinex/BepInEx.cfg) + --env-prefix ENV_PREFIX + Environment prefix (default: MODCFG_) +``` diff --git a/vpenvconf/vpenvconf/__init__.py b/env2cfg/env2cfg/__init__.py similarity index 61% rename from vpenvconf/vpenvconf/__init__.py rename to env2cfg/env2cfg/__init__.py index 3fba065..4e8b686 100644 --- a/vpenvconf/vpenvconf/__init__.py +++ b/env2cfg/env2cfg/__init__.py @@ -3,27 +3,35 @@ from configparser import ConfigParser from argparse import ArgumentParser from collections import defaultdict -from typing import Dict +from typing import Dict, Tuple logging.basicConfig( level=logging.INFO, format="%(levelname)s - %(message)s", ) -log = logging.getLogger("vpenvconf") +log = logging.getLogger("env2cfg") log.setLevel(logging.INFO) +_PRE_TRANSLATE = { + "_DOT_": ".", + "_HYPHEN_": "-", + "_PLUS_": "+", + "_UNDERSCORE_": "@UNDERSCORE@", +} + +_POST_TRANSLATE = {"@UNDERSCORE@": "_"} + + def write_config(config: ConfigParser, config_file: str) -> None: config_directory = os.path.dirname(config_file) if not os.path.isdir(config_directory): - log.info( - f"ValheimPlus config directory {config_directory} does not exist - creating" - ) + log.info(f"Mod config directory {config_directory} does not exist - creating") os.makedirs(config_directory) new_config_file = config_file + ".tmp" - log.info(f"Writing ValheimPlus config {new_config_file}") + log.info(f"Writing mod config {new_config_file}") with open(new_config_file, "w") as file: config.write(file, space_around_delimiters=False) @@ -47,27 +55,42 @@ def merge_env_with_config(config: ConfigParser, env: Dict) -> None: def get_env(prefix: str) -> Dict: - log.debug(f"Reading ValheimPlus config from env variables prefixed with {prefix}") + log.debug(f"Reading mod config from env variables prefixed with {prefix}") env_config = defaultdict(dict) env = {k[len(prefix) :]: v for k, v in os.environ.items() if k.startswith(prefix)} for k, v in env.items(): - section, key = k.split("_", 1) + section, key = var_process(k) env_config[section][key] = v log.debug(f"Found [{section}] {key} = {v} in environment") return dict(env_config) +def var_process(var: str) -> Tuple: + for in_char, out_char in _PRE_TRANSLATE.items(): + var = var.replace(in_char, out_char) + section, key = var.split("_", 1) + for in_char, out_char in _POST_TRANSLATE.items(): + section = section.replace(in_char, out_char) + key = key.replace(in_char, out_char) + return section, key + + def get_config(config_file: str) -> ConfigParser: config = ConfigParser() config.optionxform = str if os.path.isfile(config_file): - log.debug(f"Reading existing ValheimPlus config {config_file}") - config.read(config_file) + log.debug(f"Reading existing mod config {config_file}") + with open(config_file, mode="rb") as f: + content = f.read() + if content.startswith(b"\xef\xbb\xbf"): + config.read_string(content.decode("utf-8-sig")) + else: + config.read_string(content.decode("utf-8")) return config def get_arg_parser() -> ArgumentParser: - parser = ArgumentParser(description="Generate ValheimPlus config from env") + parser = ArgumentParser(description="Generate mod config from env") parser.add_argument( "--verbose", "-v", @@ -82,18 +105,15 @@ def get_arg_parser() -> ArgumentParser: def add_args(parser: ArgumentParser) -> None: parser.add_argument( "--config", - help=( - "Path to ValheimPlus config file" - " (default: /config/valheimplus/valheim_plus.cfg)" - ), + help=("Path to mod config file" " (default: /config/bepinex/BepInEx.cfg)"), dest="config_file", type=str, - default="/config/valheimplus/valheim_plus.cfg", + default="/config/bepinex/BepInEx.cfg", ) parser.add_argument( "--env-prefix", - help="Environment prefix (default: VPCFG_)", + help="Environment prefix (default: MODCFG_)", dest="env_prefix", type=str, - default="VPCFG_", + default="MODCFG_", ) diff --git a/vpenvconf/vpenvconf/__main__.py b/env2cfg/env2cfg/__main__.py similarity index 90% rename from vpenvconf/vpenvconf/__main__.py rename to env2cfg/env2cfg/__main__.py index 9a458dc..e6db811 100644 --- a/vpenvconf/vpenvconf/__main__.py +++ b/env2cfg/env2cfg/__main__.py @@ -23,7 +23,7 @@ def main() -> None: merge_env_with_config(config, env) write_config(config, args.config_file) else: - log.info("No ValheimPlus config found in env") + log.info("No BepInEx config found in env") if __name__ == "__main__": diff --git a/vpenvconf/setup.cfg b/env2cfg/setup.cfg similarity index 100% rename from vpenvconf/setup.cfg rename to env2cfg/setup.cfg diff --git a/vpenvconf/setup.py b/env2cfg/setup.py similarity index 85% rename from vpenvconf/setup.py rename to env2cfg/setup.py index 227419e..4cace45 100644 --- a/vpenvconf/setup.py +++ b/env2cfg/setup.py @@ -7,14 +7,14 @@ def read(fname): setup( - name="vpenvconf", + name="env2cfg", version="0.0.1", - description="Generate ValheimPlus config from env", + description="Generate BepInEx config from env", license="Apache 2.0", packages=find_packages(), long_description=read("README.md"), entry_points={ - "console_scripts": ["vpenvconf = vpenvconf.__main__:main"], + "console_scripts": ["env2cfg = env2cfg.__main__:main"], }, include_package_data=True, zip_safe=False, @@ -39,5 +39,5 @@ def read(fname): "Natural Language :: English", "Topic :: Utilities", ], - keywords="valheim valheimplus", + keywords="valheim valheimplus bepinex", ) diff --git a/vpenvconf/test/test_vpenvconf.py b/env2cfg/test/test_env2cfg.py similarity index 72% rename from vpenvconf/test/test_vpenvconf.py rename to env2cfg/test/test_env2cfg.py index 3261585..0ef1d32 100644 --- a/vpenvconf/test/test_vpenvconf.py +++ b/env2cfg/test/test_env2cfg.py @@ -2,7 +2,7 @@ import tempfile import logging from configparser import ConfigParser -from vpenvconf import ( +from env2cfg import ( log, get_arg_parser, add_args, @@ -17,14 +17,18 @@ add_args(parser) args = parser.parse_args() -test_var = args.env_prefix + "Server_test" -os.environ[test_var] = "true" +test_var1 = args.env_prefix + "Server_test" +test_var2 = args.env_prefix + "Logging_DOT_Console_Enabled" +test_var3 = args.env_prefix + "Logging_DOT_Console_Some_UNDERSCORE_Var" +os.environ[test_var1] = "true" +os.environ[test_var2] = "true" +os.environ[test_var3] = "false" def test_args(): assert args.verbose is False - assert args.config_file == "/config/valheimplus/valheim_plus.cfg" - assert args.env_prefix == "VPCFG_" + assert args.config_file == "/config/bepinex/BepInEx.cfg" + assert args.env_prefix == "MODCFG_" def test_get_env(): @@ -32,6 +36,8 @@ def test_get_env(): assert "Server" in env assert "test" in env["Server"] assert env["Server"]["test"] == "true" + assert env["Logging.Console"]["Enabled"] == "true" + assert env["Logging.Console"]["Some_Var"] == "false" def test_merge_env_with_config(): diff --git a/vpenvconf/tox.ini b/env2cfg/tox.ini similarity index 89% rename from vpenvconf/tox.ini rename to env2cfg/tox.ini index 18ab0d9..c381929 100644 --- a/vpenvconf/tox.ini +++ b/env2cfg/tox.ini @@ -5,11 +5,11 @@ envlist = py3-{black,syntax,tests} max-line-length=88 exclude = .git,.tox,__pycache__,.idea,.pytest_cache -application-import-names=vpenvconf +application-import-names=env2cfg ignore=E203, W503 [pytest] -addopts=--cov=vpenvconf -rs -vv +addopts=--cov=env2cfg -rs -vv testpaths= test diff --git a/valheim-bootstrap b/valheim-bootstrap index fee59d3..ce3eacf 100755 --- a/valheim-bootstrap +++ b/valheim-bootstrap @@ -21,10 +21,7 @@ fi # check if we are supposed to wipe our data directories if [ "$DEBUG_START_FRESH" = true ]; then warn "Wiping all data directories (DEBUG_START_FRESH: $DEBUG_START_FRESH)" - rm -rf "$valheim_download_path" - rm -rf "$valheim_install_path" - rm -rf "$vp_download_path" - rm -rf "$vp_install_path" + rm -rf "/opt/valheim/*" fi # check if we are supposed to reinstall ValheimPlus @@ -34,6 +31,13 @@ if [ "$DEBUG_REINSTALL_VALHEIM_PLUS" = true ]; then rm -rf "$vp_install_path" fi +# check if we are supposed to reinstall BepInEx +if [ "$DEBUG_REINSTALL_BEPINEX" = true ]; then + warn "Reinstalling BepInEx mod (DEBUG_REINSTALL_BEPINEX: $DEBUG_REINSTALL_BEPINEX)" + rm -rf "$bepinex_download_path" + rm -rf "$bepinex_install_path" +fi + # Output image commit version on startup if [ -f "$git_commit_file" ]; then commit=$(< "$git_commit_file") @@ -45,11 +49,27 @@ fi mkdir -p "$valheim_download_path" mkdir -p "$valheim_install_path" +# Mod support +if [ "$VALHEIM_PLUS" = true ] && [ "$BEPINEX" = true ]; then + error "Configuration error: enable ValheimPlus or BepInEx mod support but not both - aborting startup" + supervisorctl shutdown + exit 1 +fi + if [ "$VALHEIM_PLUS" = true ]; then mkdir -p "$vp_download_path" mkdir -p "$vp_install_path" if [ -d "$vp_config_path" ]; then write_valheim_plus_config + write_bepinex_config + fi +fi + +if [ "$BEPINEX" = true ]; then + mkdir -p "$bepinex_download_path" + mkdir -p "$bepinex_install_path" + if [ -d "$bepinex_config_path" ]; then + write_bepinex_config fi fi diff --git a/valheim-plus-updater b/valheim-plus-updater index 349e5b0..e5c719f 100755 --- a/valheim-plus-updater +++ b/valheim-plus-updater @@ -9,137 +9,29 @@ . /usr/local/etc/valheim/defaults . /usr/local/etc/valheim/common -main() { - create_directory_structure - check_for_update -} - -create_directory_structure() { - mkdir -p "$vp_download_path" "$vp_install_path" -} - - -check_for_update() { - cd "$vp_download_path" || fatal "Could not cd $vp_download_path" +main() { local api_response local download_url local remote_updated_at - local remote_size + if ! api_response=$(curl -sfSL https://api.github.com/repos/valheimPlus/ValheimPlus/releases/latest); then fatal "Error: could not retrieve ValheimPlus release info from Github API" fi api_response=$(jq -r ".assets[] | select(.name == \"$vp_zipfile\")" <<< "$api_response" ) download_url=$(jq -r ".browser_download_url" <<< "$api_response" ) remote_updated_at=$(jq -r ".updated_at" <<< "$api_response" ) - remote_size=$(jq -r ".size" <<< "$api_response") - - if [ -f "$vp_zipfile" ] && [ -f "$vp_zipfile.updated_at" ] && [ -f "$vp_zipfile.installed_at" ]; then - local_updated_at=$(< "$vp_zipfile.updated_at") - local_installed_at=$(< "$vp_zipfile.installed_at") - local_size=$(stat --format="%s" "$vp_zipfile") - if [ "$local_updated_at" = "$remote_updated_at" ] && [ "$local_size" = "$remote_size" ] && [ "$local_updated_at" = "$local_installed_at" ]; then - debug "Local ValheimPlus archive is identical to remote archive and was successfully installed - no update required" - else - info "Local ValheimPlus archive with size $local_size and update date $local_updated_at differs from remote size $remote_size and date $remote_updated_at or failed to successfully install - updating" - prepare_valheim_plus "$download_url" "$remote_updated_at" - fi - else - info "Fresh ValheimPlus install" - prepare_valheim_plus "$download_url" "$remote_updated_at" - fi - - # The control file $vp_mergefile is either created - # in prepare_valheim_plus() if ValheimPlus is being installed for - # the first time or an update is available, or - # it is created by valheim-updater if a Valheim server update - # was downloaded and the mod needs to be applied to it. - if [ -f "$vp_mergefile" ]; then - info "Valheim dedicated server or ValheimPlus got updated - extracting and merging installation files" - (set -e; extract_valheim_plus && merge_valheim_plus) - # shellcheck disable=SC2181 - if [ $? -eq 0 ]; then - debug "Successfully installed ValheimPlus mod" - cp -f "$vp_zipfile.updated_at" "$vp_zipfile.installed_at" - rm -f "$vp_mergefile" - else - error "Failed to extract and install ValheimPlus mod - retrying later" - fi - fi -} - - -prepare_valheim_plus() { - local download_url="$1" - local updated_at="$2" - download_valheim_plus "$download_url" "$updated_at" \ - && touch "$vp_mergefile" -} - - -merge_valheim_plus() { - local config_file - local pkg_config_dir - local dest_file - debug "Merging Valheim server and ValheimPlus mod" - # remove any old ValheimPlus install directories - rm -rf "$vp_install_path.tmp" "$vp_install_path.old" - # create a new install directory where we will stage the new version - mkdir -p "$vp_install_path.tmp" - # rsync all Valheim dedicated server files - rsync -a --itemize-changes --exclude server_exit.drp --exclude steamapps "$valheim_download_path/" "$vp_install_path.tmp" - # rsync all ValheimPlus mod files on top of the dedicated server files - rsync -a --itemize-changes "$vp_download_path/extracted/" "$vp_install_path.tmp" - # if /config/valheimplus/ does not exist copy the default config from the ZIP archive - mkdir -p "$vp_config_path" - pkg_config_dir="$vp_install_path.tmp/BepInEx/config" - if [ -d "$pkg_config_dir" ]; then - cd "$pkg_config_dir" || fatal "Could not cd $pkg_config_dir" - for config_file in *; do - dest_file="$vp_config_path/$config_file" - # always copy the config that came with the latest ZIP archive to valheim_plus.cfg.default - cp -f "$config_file" "$dest_file.default" - if [ ! -f "$dest_file" ]; then - debug "Config $dest_file does not exist - copying from archive" - cp -f "$config_file" "$dest_file" - if [ "$config_file" = "valheim_plus.cfg" ]; then - write_valheim_plus_config - fi - fi - done - cd - || fatal "Could not cd -" - fi - # ensure config file permissions - ensure_permissions - # remove the config folder within the server directory and symlink it to /config - rm -rf "$pkg_config_dir" - ln -s "$vp_config_path" "$pkg_config_dir" - # move an existing copy of ValheimPlus to the .old extension - if [ -d "$vp_install_path" ]; then - mv -f "$vp_install_path" "$vp_install_path.old" - fi - # move the staging folder to the live folder and signal valheim-updater to restart the server - mv "$vp_install_path.tmp" "$vp_install_path" - write_restart_file updated -} - - -download_valheim_plus() { - local download_url="$1" - local updated_at="$2" - local download_path="$vp_download_path/$vp_zipfile" - debug "Downloading $download_url to $download_path" - curl -sfSL -o "$download_path" "$download_url" \ - && echo "$updated_at" > "$download_path.updated_at" -} - -extract_valheim_plus() { - cd "$vp_download_path" || fatal "Could not cd $vp_download_path" - debug "Extracting downloaded ValheimPlus ZIP archive" - rm -rf extracted - mkdir -p extracted - unzip -d extracted/ "$vp_zipfile" + check_for_mod_update \ + "$download_url" \ + "$remote_updated_at" \ + "$vp_zipfile" \ + "$vp_mergefile" \ + "$vp_download_path" \ + "$vp_config_path" \ + "extracted" \ + "$vp_install_path" \ + "ValheimPlus" } diff --git a/valheim-server b/valheim-server index ea68b91..d6d65cb 100755 --- a/valheim-server +++ b/valheim-server @@ -14,6 +14,7 @@ valheim_server_pid=-1 timeout=29 kill_signal=TERM password_args=(-password "$SERVER_PASS") +mod_name=none if [ "$VALHEIM_PLUS" = true ]; then cd "$vp_install_path" || fatal "Could not cd $vp_install_path" @@ -24,7 +25,23 @@ if [ "$VALHEIM_PLUS" = true ]; then export LD_LIBRARY_PATH="$vp_install_path/linux64/:$vp_install_path/doorstop_libs/" SERVER_LD_PRELOAD=libdoorstop_x64.so valheim_server="$vp_install_path/valheim_server.x86_64" - [ -z "$SERVER_PASS" ] && password_args=() + if [ -z "$SERVER_PASS" ]; then + password_args=() + fi + mod_name="ValheimPlus" +elif [ "$BEPINEX" = true ]; then + cd "$bepinex_install_path" || fatal "Could not cd $bepinex_install_path" + rm -rf "$bepinex_install_path.old" + export DOORSTOP_ENABLE=TRUE + export DOORSTOP_INVOKE_DLL_PATH="./BepInEx/core/BepInEx.Preloader.dll" + export DOORSTOP_CORLIB_OVERRIDE_PATH="./unstripped_corlib" + export LD_LIBRARY_PATH="$bepinex_install_path/linux64/:$bepinex_install_path/doorstop_libs/" + SERVER_LD_PRELOAD=libdoorstop_x64.so + valheim_server="$bepinex_install_path/valheim_server.x86_64" + if [ -z "$SERVER_PASS" ]; then + password_args=() + fi + mod_name="BepInEx" else cd "$valheim_install_path" || fatal "Could not cd $valheim_install_path" export LD_LIBRARY_PATH="$valheim_install_path/linux64/" @@ -86,7 +103,7 @@ wait_for_server_listening() { run_server() { pre_server_run_hook info "Running Valheim Server" - debug "Server config is name: $SERVER_NAME, port: $SERVER_PORT/udp, world: $WORLD_NAME, public: $SERVER_PUBLIC, V+ mod: $VALHEIM_PLUS" + debug "Server config is name: $SERVER_NAME, port: $SERVER_PORT/udp, world: $WORLD_NAME, public: $SERVER_PUBLIC, mod: $mod_name" update_server_status starting # shellcheck disable=SC2086 diff --git a/valheim-updater b/valheim-updater index d989c60..3c54d49 100755 --- a/valheim-updater +++ b/valheim-updater @@ -58,11 +58,11 @@ update() { rsync -a --itemize-changes --delete --exclude server_exit.drp --exclude steamapps "$valheim_download_path/" "$valheim_install_path" | tee "$logfile" if grep '^[*>]' "$logfile" > /dev/null 2>&1; then info "Valheim Server was updated - restarting" - check_valheim_plus updated + check_mods updated write_restart_file updated else info "Valheim Server is already the latest version" - check_valheim_plus uptodate + check_mods uptodate if [ "$just_started" = true ]; then write_restart_file just_started fi @@ -73,20 +73,34 @@ update() { } -check_valheim_plus() { - if [ "$VALHEIM_PLUS" = true ]; then - debug "ValheimPlus is enabled - running updater" - if [ "$1" = updated ]; then - info "Valheim Server was updated from Steam - signaling ValheimPlus updater to merge updated files" - touch "$vp_mergefile" +check_mods() { + local valheim_server_update_status=$1 + check_mod "$valheim_server_update_status" "ValheimPlus" "$VALHEIM_PLUS" "$vp_mergefile" "$vp_install_path" "$vp_updater" + check_mod "$valheim_server_update_status" "BepInEx" "$BEPINEX" "$bepinex_mergefile" "$bepinex_install_path" "$bepinex_updater" +} + + +check_mod() { + local valheim_server_update_status=$1 + local mod_name=$2 + local mod_enabled=$3 + local mod_mergefile=$4 + local mod_install_path=$5 + local mod_updater=$6 + + if [ "$mod_enabled" = true ]; then + debug "$mod_name is enabled - running updater" + if [ "$valheim_server_update_status" = updated ]; then + info "Valheim Server was updated from Steam - signaling $mod_name updater to merge updated files" + touch "$mod_mergefile" fi - just_started=$just_started /usr/local/bin/valheim-plus-updater + just_started=$just_started "$mod_updater" else - if [ "$1" = updated ] && [ -d "$vp_install_path" ]; then - debug "ValheimPlus currently disabled but previously installed - keeping installation fresh" - debug "If this is unwanted remove $vp_install_path" - touch "$vp_mergefile" - just_started=$just_started /usr/local/bin/valheim-plus-updater + if [ "$valheim_server_update_status" = updated ] && [ -d "$mod_install_path" ]; then + debug "$mod_name currently disabled but previously installed - keeping installation fresh" + debug "If this is unwanted remove $mod_install_path" + touch "$mod_mergefile" + just_started=$just_started "$mod_updater" fi fi } @@ -100,6 +114,8 @@ download_valheim() { # This works around the `Unable to determine CPU Frequency. Try defining CPU_MHZ.` steamcmd issue (#184). verify_cpu_mhz() { + local float_regex + local cpu_mhz float_regex="^([0-9]+\\.?[0-9]*)\$" cpu_mhz=$(grep "^cpu MHz" /proc/cpuinfo | head -1 | cut -d : -f 2 | xargs) if [ -n "$cpu_mhz" ] && [[ "$cpu_mhz" =~ $float_regex ]] && [ "${cpu_mhz%.*}" -gt 0 ]; then @@ -113,7 +129,10 @@ verify_cpu_mhz() { verify_memory() { - mem=$(awk ' + local mem_info + local mem_total + local mem_min=4000000 + mem_info=$(awk ' BEGIN { total=0 free=0 @@ -131,7 +150,12 @@ verify_memory() { print total"/"free"/"available } ' /proc/meminfo) - debug "Memory total/free/available: $mem" + debug "Memory total/free/available: $mem_info" + mem_total=${mem_info//\/*} + if [ "$mem_total" -lt $mem_min ]; then + mem_total=$(iec_size_format "$((mem_total*1024))") + error "$mem_total is not enough memory - read https://github.com/lloesche/valheim-server-docker#system-requirements" + fi } diff --git a/vpenvconf/README.md b/vpenvconf/README.md deleted file mode 100644 index 9724816..0000000 --- a/vpenvconf/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vpenvconf -Generate ValheimPlus configuration from env - -``` -usage: vpenvconf [-h] [--verbose] [--config CONFIG_FILE] [--env-prefix ENV_PREFIX] - -Generate ValheimPlus config from env - -optional arguments: - -h, --help show this help message and exit - --verbose, -v Verbose logging - --config CONFIG_FILE Path to ValheimPlus config file (default: /config/valheimplus/valheim_plus.cfg) - --env-prefix ENV_PREFIX - Environment prefix (default: VPCFG_) -```