diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..36140ff --- /dev/null +++ b/.dockerignore @@ -0,0 +1,9 @@ +.git +.gitignore +.github +.roo +openspec +assets +README.md +CHANGELOG.md +.gemini diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..7d1ecf5 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,15 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" + - package-ecosystem: "docker" + directory: "/" + schedule: + interval: "monthly" diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index dd45635..bd905f9 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -3,16 +3,101 @@ name: Docker Image CI on: push: branches: [ "main" ] + tags: [ "v*.*.*" ] pull_request: branches: [ "main" ] -jobs: +permissions: + packages: write + contents: write + +env: + GHCR_IMAGE: ghcr.io/${{ github.repository }} +jobs: build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push to GHCR + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: ${{ env.GHCR_IMAGE }}:${{ github.sha }} + cache-from: type=gha + cache-to: type=gha,mode=max + + test: + needs: build runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Pull image for testing + run: docker pull ${{ env.GHCR_IMAGE }}:${{ github.sha }} + + - name: Run E2E Startup Test + run: ./scripts/test-startup.sh ${{ env.GHCR_IMAGE }}:${{ github.sha }} + + - name: Show logs on failure + if: failure() + run: | + docker ps -a + # The container name has a timestamp, so we list all to find it + docker logs $(docker ps -a -q --filter ancestor=${{ env.GHCR_IMAGE }}:${{ github.sha }}) || true + + publish: + needs: test + if: startsWith(github.ref, 'refs/tags/') + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - name: Build the Docker image - run: docker build . --file Dockerfile --tag vrising:$(date +%s) + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Pull image from GHCR + run: docker pull ${{ env.GHCR_IMAGE }}:${{ github.sha }} + + - name: Tag and push to Docker Hub + run: | + TAG_NAME=${GITHUB_REF#refs/tags/} + DOCKERHUB_REPO="${{ secrets.DOCKERHUB_USERNAME }}/vrising-dedicated" + + docker tag ${{ env.GHCR_IMAGE }}:${{ github.sha }} $DOCKERHUB_REPO:latest + docker tag ${{ env.GHCR_IMAGE }}:${{ github.sha }} $DOCKERHUB_REPO:$TAG_NAME + + docker push $DOCKERHUB_REPO:latest + docker push $DOCKERHUB_REPO:$TAG_NAME + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + generate_release_notes: true diff --git a/.github/workflows/prune-registries.yml b/.github/workflows/prune-registries.yml new file mode 100644 index 0000000..2b9cbdd --- /dev/null +++ b/.github/workflows/prune-registries.yml @@ -0,0 +1,51 @@ +name: Prune Registries + +on: + schedule: + - cron: '0 0 * * 0' # Every Sunday at midnight + workflow_dispatch: # Allow manual triggering + +jobs: + prune-ghcr: + runs-on: ubuntu-latest + steps: + - name: Prune untagged GHCR images + uses: vlaurin/action-ghcr-prune@main + with: + token: ${{ secrets.PAT_WITH_DELETE_PACKAGES_SCOPE }} + user: ${{ github.actor }} + container: docker-vrising + prune-untagged: true + dry-run: false + + prune-dockerhub: + runs-on: ubuntu-latest + steps: + - name: Prune old commit-SHA tags from Docker Hub + env: + DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} + DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} + run: | + echo "Authenticating with Docker Hub..." + TOKEN=$(curl -s -H "Content-Type: application/json" -X POST -d '{"username": "'${DOCKERHUB_USERNAME}'", "password": "'${DOCKERHUB_TOKEN}'"}' https://hub.docker.com/v2/users/login/ | jq -r .token) + + if [ "$TOKEN" == "null" ] || [ -z "$TOKEN" ]; then + echo "Failed to get Docker Hub token. Please check your secrets." + exit 1 + fi + + REPO="${DOCKERHUB_USERNAME}/vrising-dedicated" + echo "Fetching tags for ${REPO}..." + + # Fetch up to 100 tags to prune old commit SHAs + TAGS=$(curl -s -H "Authorization: JWT ${TOKEN}" "https://hub.docker.com/v2/repositories/${REPO}/tags/?page_size=100" | jq -r '.results|.[]|.name') + + for TAG in $TAGS; do + # Keep 'latest' and semantic version tags (e.g. v1.0.0, 1.0.0) + if [[ "$TAG" != "latest" ]] && [[ ! "$TAG" =~ ^v?[0-9]+\.[0-9]+\.[0-9]+.*$ ]]; then + echo "Deleting legacy/commit-SHA tag: $TAG" + curl -s -X DELETE -H "Authorization: JWT ${TOKEN}" "https://hub.docker.com/v2/repositories/${REPO}/tags/${TAG}/" + else + echo "Keeping official tag: $TAG" + fi + done diff --git a/.github/workflows/update-vrising.yml b/.github/workflows/update-vrising.yml new file mode 100644 index 0000000..41bee57 --- /dev/null +++ b/.github/workflows/update-vrising.yml @@ -0,0 +1,34 @@ +name: Check for V Rising Updates + +on: + schedule: + - cron: '0 0 * * 0' # Every Sunday at midnight + workflow_dispatch: + +jobs: + check-vrising-update: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Get latest V Rising buildid + id: vrising_build + run: | + LATEST_BUILD=$(curl -s https://api.steamcmd.net/v1/info/1828900 | jq -r '.data."1828900".depots.branches.public.buildid') + echo "latest=$LATEST_BUILD" >> "$GITHUB_OUTPUT" + + - name: Update Dockerfile + if: steps.vrising_build.outputs.latest != 'null' && steps.vrising_build.outputs.latest != '' + run: | + LATEST_BUILD="${{ steps.vrising_build.outputs.latest }}" + sed -i "s/ARG VRISING_BUILD_ID=\".*\"/ARG VRISING_BUILD_ID=\"$LATEST_BUILD\"/" Dockerfile + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v8 + with: + commit-message: "chore(deps): update v rising build to ${{ steps.vrising_build.outputs.latest }}" + title: "Update V Rising Build ID to ${{ steps.vrising_build.outputs.latest }}" + body: "Automated update of V Rising build ID in the Dockerfile to trigger a new image build." + branch: "update-vrising" + delete-branch: true diff --git a/.github/workflows/update-wine.yml b/.github/workflows/update-wine.yml new file mode 100644 index 0000000..c225035 --- /dev/null +++ b/.github/workflows/update-wine.yml @@ -0,0 +1,42 @@ +name: Check for Wine Updates + +on: + schedule: + - cron: '0 0 1 * *' # 1st of every month + workflow_dispatch: + +jobs: + check-wine-update: + runs-on: ubuntu-24.04 + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Add WineHQ Repository + run: | + sudo mkdir -pm755 /etc/apt/keyrings + sudo wget -O /etc/apt/keyrings/winehq-archive.key https://dl.winehq.org/wine-builds/winehq.key + sudo wget -NP /etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/ubuntu/dists/noble/winehq-noble.sources + sudo dpkg --add-architecture i386 + sudo apt-get update + + - name: Get latest Wine version + id: wine_version + run: | + LATEST_WINE=$(apt-cache policy winehq-stable | grep Candidate | awk '{print $2}') + echo "latest=$LATEST_WINE" >> "$GITHUB_OUTPUT" + + - name: Update Dockerfile + if: steps.wine_version.outputs.latest != '' + run: | + LATEST_WINE="${{ steps.wine_version.outputs.latest }}" + sed -i "s/ARG WINE_VERSION=\".*\"/ARG WINE_VERSION=\"$LATEST_WINE\"/" Dockerfile + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v8 + with: + commit-message: "chore(deps): update wine to ${{ steps.wine_version.outputs.latest }}" + title: "Update Wine to ${{ steps.wine_version.outputs.latest }}" + body: "Automated update of Wine version in the Dockerfile." + branch: "update-wine" + delete-branch: true diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..764e878 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,49 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## [2026-02-28] + +- Added native Docker `HEALTHCHECK` using a UDP ping to the V Rising Query Port. +- Added documentation for running a persistent RCON sidecar (`gorcon/rcon-cli`) using Docker Compose. +- Standardized the default `SERVERNAME` to `vrising-dedicated` across all scripts and configuration examples. +- Standardized the default timezone (`TZ`) to `Europe/Rome`. +- Removed legacy `--entrypoint` workaround commands from all documentation examples. + +## [2026-02-27] + +- Added automated GitHub Actions workflows to check for Wine and V Rising updates and create Pull Requests. +- Updated Dockerfile to use explicit `ARG` version tracking for Wine and V Rising to support automated updates. +- Optimized Ubuntu 24.04 and Wine environment for improved server stability. +- Standardized LF line endings for all container-internal scripts to prevent execution errors. +- Automated Steam license acceptance during Docker build process. +- Fixed SteamCMD configuration to ensure reliable server installation and updates. +- Improved CI/CD pipeline with automated E2E testing +- Standardized project structure and documentation. + +## [026-02-21] + +Docker image rebuild + tested on a linux dockerhost (unraid).
+For now, u need to add this to the compose file:
+`entrypoint: ["/bin/bash", "-c", "sed -i 's/\\r//g' /start.sh && exec /bin/bash /start.sh"]`
+Thx [laerdev](https://github.com/laerdev) for the fix.
+ +## [2025-08-01] + +- Just tested the latest image for V-Rising 1.1. +- Log will be spammed with these messages. Feel free to give me a solution here.
+ 01b4:fixme:winsock:server_ioctl_sock Unsupported ioctl 4004747b (device=4004 access=1 func=d1e method=3)
+ vrising-1 | 01b4:fixme:winsock:WSAIoctl unsupported WS_IOCTL cmd (SIO_IDEAL_SEND_BACKLOG_QUERY) +- There is no way to continue a game from 1.0. I just checked with the discord community. +- Still an issue: when the server is passworded, joining via Steam seems not possible. Use the ingame server list to join. + +## [2024-05-16] + +- Merged with [pull65](https://github.com/TrueOsiris/docker-vrising/pull/65) from [Killerherts](https://github.com/killerherts).
+ Logs older than 30 days are cleaned up on server start. +- Merged with [pull52](https://github.com/TrueOsiris/docker-vrising/pull/52) from [Diyagi](https://github.com/diyagi).
+ Previous container version can still be grabbed via [trueosiris/vrising:2.0](https://hub.docker.com/layers/TrueOsiris/vrising/2.0/images/sha256-b9142d6f653685c92e25745f48cd205a1ffc7ed4aedef19011b03ab2a03a33c6?context=repo)
+ Main fixes are: clean shutdown & complete log to container log. Kudos! +- Added date to the logfile name, so per server launch, a logfile will be created. For now, they will not be automatically cleaned up. +- If you're experiencing [this issue](https://github.com/TrueOsiris/docker-vrising/issues/51) with "[476:488:20240511,134828.926:ERROR http_transport_win.cc:388] HTTP status 403" in the log, pull [TrueOsiris/vrising-dedicated:display](https://hub.docker.com/layers/TrueOsiris/vrising/display/images/sha256-592b9ace78b7228c08134804fa94b0f47766bb9202d86048a0a4ded81f765cda?context=repo) which uses xvfb. +- If you're experiencing [this issue](https://github.com/TrueOsiris/docker-vrising/issues/43) with "wine: Assertion failed at address 00007F79E2C9EA7C (thread 0094)" in the log, u might need the latest wine from winehq, therefore grab [TrueOsiris/vrising-dedicated:winehq](https://hub.docker.com/layers/TrueOsiris/vrising/winehq/images/sha256-f7f662258b30d6250d16718aa008a95b868336c92fdd98e56fd39bbca5626f8c?context=repo) diff --git a/Dockerfile b/Dockerfile index e4ffef2..2729717 100755 --- a/Dockerfile +++ b/Dockerfile @@ -1,38 +1,86 @@ -FROM ubuntu:22.04 -LABEL maintainer="Tim Chaubet" -VOLUME ["/mnt/vrising/server", "/mnt/vrising/persistentdata"] - +FROM --platform=linux/amd64 ubuntu:24.04 AS base +LABEL maintainer="Davide Mirtillo" ARG DEBIAN_FRONTEND="noninteractive" -RUN apt update -y && \ - apt-get upgrade -y && \ - apt-get install -y apt-utils && \ - apt-get install -y software-properties-common \ - tzdata && \ - add-apt-repository multiverse && \ + +# 1. Install base dependencies and setup locales +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + apt-utils \ + software-properties-common \ + tzdata \ + wget \ + ca-certificates \ + locales && \ + locale-gen en_US.UTF-8 && \ + rm -rf /var/lib/apt/lists/* + +ENV LANG=en_US.UTF-8 \ + LANGUAGE=en_US:en \ + LC_ALL=en_US.UTF-8 + +# 2. Setup WineHQ and i386 +FROM base AS wine-setup +ARG WINE_VERSION="11.0.0.0~noble-1" +RUN mkdir -pm755 /etc/apt/keyrings && \ + wget -O /etc/apt/keyrings/winehq-archive.key https://dl.winehq.org/wine-builds/winehq.key && \ + wget -NP /etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/ubuntu/dists/noble/winehq-noble.sources && \ dpkg --add-architecture i386 && \ - apt update -y && \ - apt-get upgrade -y -RUN useradd -m steam && cd /home/steam && \ + apt-get update && \ + apt-get install -y --no-install-recommends \ + winehq-stable=${WINE_VERSION} \ + wine-stable=${WINE_VERSION} \ + wine-stable-amd64=${WINE_VERSION} \ + wine-stable-i386=${WINE_VERSION} && \ + rm -rf /var/lib/apt/lists/* + +# 3. Install latest winetricks from source +FROM wine-setup AS winetricks-setup +RUN apt-get update && \ + apt-get install -y --no-install-recommends wget ca-certificates && \ + (cd "$(mktemp -d)" && \ + echo '#!/bin/sh\n\ncd "$(mktemp -d)"\nwget https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks\nwget https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks.bash-completion\nchmod +x winetricks\nmv winetricks /usr/bin\nmv winetricks.bash-completion /usr/share/bash-completion/completions/winetricks' > update_winetricks && \ + chmod +x update_winetricks && \ + mv update_winetricks /usr/bin/ && \ + /usr/bin/update_winetricks) && \ + rm -rf /var/lib/apt/lists/* + +# 4. Install remaining dependencies and SteamCMD +FROM winetricks-setup AS final +ARG VRISING_BUILD_ID="8148398" +RUN add-apt-repository multiverse && \ + apt-get update && \ echo steam steam/question select "I AGREE" | debconf-set-selections && \ echo steam steam/license note '' | debconf-set-selections && \ - apt purge steam steamcmd && \ - apt install -y gdebi-core \ - libgl1-mesa-glx:i386 \ - wget && \ - apt install -y steam \ - steamcmd && \ - ln -s /usr/games/steamcmd /usr/bin/steamcmd -#RUN apt install -y mono-complete -RUN apt install -y wine \ - winbind \ - winetricks -RUN apt install -y xserver-xorg \ - xvfb -RUN apt update -y && apt install -y jq -RUN rm -rf /var/lib/apt/lists/* && \ - apt clean && \ - apt autoremove -y - -COPY start.sh /start.sh -RUN chmod +x /start.sh -CMD ["/start.sh"] + apt-get install -y --no-install-recommends \ + gdebi-core \ + jq \ + gosu \ + xvfb \ + xserver-xorg \ + winbind \ + libgl1-mesa-dri:i386 \ + libgl1:i386 \ + netcat-openbsd \ + steam \ + steamcmd && \ + # Setup symlinks + [ -e /usr/bin/steamcmd ] || ln -s /usr/games/steamcmd /usr/bin/steamcmd && \ + [ -e /usr/bin/wine ] || ln -s /opt/wine-stable/bin/wine /usr/bin/wine && \ + # In Wine 11.0, 'wine' is the 64-bit binary. Link it to wine64 for script compatibility. + [ -e /usr/bin/wine64 ] || ln -s /opt/wine-stable/bin/wine /usr/bin/wine64 && \ + [ -e /usr/bin/wineserver ] || ln -s /opt/wine-stable/bin/wineserver /usr/bin/wineserver && \ + # Create steam user + useradd -m -s /bin/bash steam && \ + # Clean up + apt-get purge -y --auto-remove software-properties-common && \ + rm -rf /var/lib/apt/lists/* && \ + apt-get clean + +# Setup the start script +COPY --chmod=755 start.sh /start.sh +RUN sed -i 's/\r$//' /start.sh + +HEALTHCHECK --interval=30s --timeout=10s --start-period=120s --retries=3 \ + CMD nc -z -u 127.0.0.1 ${QUERYPORT:-9877} || exit 1 + +ENTRYPOINT ["/start.sh"] diff --git a/README.md b/README.md index f34e832..887de83 100755 --- a/README.md +++ b/README.md @@ -1,232 +1,52 @@

- Iroh + V Rising Docker -

Dockerized V Rising dedicated server in an Ubuntu 22.04 container with Wine.

+

A high-performance, easy-to-use Dockerized V Rising dedicated server.

-[![Docker](https://img.shields.io/badge/Docker-2496ED?logo=docker&logoColor=white)](https://hub.docker.com/r/trueosiris/vrising) -[![GitHub](https://img.shields.io/badge/GitHub-181717?logo=github&logoColor=white)](https://github.com/TrueOsiris/docker-vrising) -[![Wine](https://img.shields.io/badge/Wine-800000?logo=wine&logoColor=white)](https://www.winehq.org/) -[![Steam](https://img.shields.io/badge/Steam-1b2838?logo=steam&logoColor=white)](https://store.steampowered.com/app/1604030/V_Rising/) -[![V Rising](https://img.shields.io/badge/V%20Rising-1604030-8A0303?logo=steam&logoColor=white)](https://store.steampowered.com/app/1604030/V_Rising/) -[![Docker Pulls](https://img.shields.io/docker/pulls/trueosiris/vrising?logo=docker&label=pulls)](https://hub.docker.com/r/trueosiris/vrising) -[![Docker Stars](https://img.shields.io/docker/stars/trueosiris/vrising?logo=docker&label=stars)](https://hub.docker.com/r/trueosiris/vrising) -[![Docker Image Size](https://img.shields.io/docker/image-size/trueosiris/vrising/latest?logo=docker&label=image%20size)](https://hub.docker.com/r/trueosiris/vrising) -[![GitHub stars](https://img.shields.io/github/stars/TrueOsiris/docker-vrising?logo=github&label=stars)](https://github.com/TrueOsiris/docker-vrising) -[![GitHub forks](https://img.shields.io/github/forks/TrueOsiris/docker-vrising?logo=github&label=forks)](https://github.com/TrueOsiris/docker-vrising) -[![GitHub open issues](https://img.shields.io/github/issues/TrueOsiris/docker-vrising?logo=github&label=open%20issues)](https://github.com/TrueOsiris/docker-vrising/issues) -[![GitHub closed issues](https://img.shields.io/github/issues-closed/TrueOsiris/docker-vrising?logo=github&label=closed%20issues)](https://github.com/TrueOsiris/docker-vrising/issues?q=is%3Aissue+is%3Aclosed) -[![GitHub last-commit](https://img.shields.io/github/last-commit/TrueOsiris/docker-vrising?logo=github&label=last%20commit)](https://github.com/TrueOsiris/docker-vrising/commits) - - -## Updates - -### image 2026-02-21 - -Docker image rebuild + tested on a linux dockerhost (unraid).
-For now, u need to add this to the compose file:
-`entrypoint: ["/bin/bash", "-c", "sed -i 's/\\r//g' /start.sh && exec /bin/bash /start.sh"]`
-Thx [laerdev](https://github.com/laerdev) for the fix.
- -### image 2025-08-01 - -- Just tested the latest image for V-Rising 1.1. -- Log will be spammed with these messages. Feel free to give me a solution here.
- 01b4:fixme:winsock:server_ioctl_sock Unsupported ioctl 4004747b (device=4004 access=1 func=d1e method=3)
- vrising-1 | 01b4:fixme:winsock:WSAIoctl unsupported WS_IOCTL cmd (SIO_IDEAL_SEND_BACKLOG_QUERY) -- There is no way to continue a game from 1.0. I just checked with the discord community. -- Still an issue: when the server is passworded, joining via Steam seems not possible. Use the ingame server list to join. - -### image 2024-05-16 ([trueosiris/vrising:2.1](https://hub.docker.com/layers/trueosiris/vrising/2.1/images/sha256-00639c82158711d868f41750aa43f605bd35f5b775725137ef3b0b10ba80b52e?context=repo) or [latest](https://hub.docker.com/layers/trueosiris/vrising/latest/images/sha256-00639c82158711d868f41750aa43f605bd35f5b775725137ef3b0b10ba80b52e?context=repo)) - -- Merged with [pull65](https://github.com/TrueOsiris/docker-vrising/pull/65) from [Killerherts](https://github.com/killerherts).
- Logs older than 30 days are cleaned up on server start. -- Merged with [pull52](https://github.com/TrueOsiris/docker-vrising/pull/52) from [Diyagi](https://github.com/diyagi).
- Previous container version can still be grabbed via [trueosiris/vrising:2.0](https://hub.docker.com/layers/trueosiris/vrising/2.0/images/sha256-b9142d6f653685c92e25745f48cd205a1ffc7ed4aedef19011b03ab2a03a33c6?context=repo)
- Main fixes are: clean shutdown & complete log to container log. Kudos! -- Added date to the logfile name, so per server launch, a logfile will be created. For now, they will not be automatically cleaned up. -- If you're experiencing [this issue](https://github.com/TrueOsiris/docker-vrising/issues/51) with "[476:488:20240511,134828.926:ERROR http_transport_win.cc:388] HTTP status 403" in the log, pull [trueosiris/vrising:display](https://hub.docker.com/layers/trueosiris/vrising/display/images/sha256-592b9ace78b7228c08134804fa94b0f47766bb9202d86048a0a4ded81f765cda?context=repo) which uses xvfb. -- If you're experiencing [this issue](https://github.com/TrueOsiris/docker-vrising/issues/43) with "wine: Assertion failed at address 00007F79E2C9EA7C (thread 0094)" in the log, u might need the latest wine from winehq, therefore grab [trueosiris/vrising:winehq](https://hub.docker.com/layers/trueosiris/vrising/winehq/images/sha256-f7f662258b30d6250d16718aa008a95b868336c92fdd98e56fd39bbca5626f8c?context=repo) - -## Environment variables - - -| Variable | Key | Description | -| ------------ | ------------------------ | ----------------------------------------------------------------------------------- | -| TZ | Europe/Brussels | timezone for ntpdate | -| SERVERNAME | published servername | mandatory setting that overrules the ServerHostSettings.json entry | -| WORLDNAME | optional worldname | default = world1. No real need to alter this. saves will be in a subdir WORLDNAME | -| GAMEPORT | optional game udp port | to overrule Port in ServerHostSettings.json config | -| QUERYPORT | optional query port | to overrule QueryPort in ServerHostSettings.json config | -| LOGDAYS | optional lifetime of logfiles | overrule default of 30 days | -| BRANCH | optional server version | Allows to run the server version legacy-1.0.x-pc | - -## Ports - - -| Exposed Container port | Type | Default | -| ---------------------- | ---- | ------- | -| 9876 | UDP | ✔️ | -| 9877 | UDP | ✔️ | - -## Volumes - - -| Volume | Container path | Description | -| -------------------- | ----------------------------- | ----------------------------------------- | -| steam install path | /mnt/vrising/server | path to hold the dedicated server files | -| world | /mnt/vrising/persistentdata | path that holds the world files | - -## Docker cli - -```bash -docker run -d --name='vrising' \ ---net='bridge' \ ---restart=unless-stopped \ --e WINEDEBUG=fixme-all \ --e TZ="Europe/Paris" \ --e SERVERNAME="trueosiris-V" \ --v '/path/on/host/server':'/mnt/vrising/server':'rw' \ --v '/path/on/host/persistentdata':'/mnt/vrising/persistentdata':'rw' \ --p 9876:9876/udp \ --p 9877:9877/udp \ ---entrypoint "/bin/bash" \ -trueosiris/vrising \ --c "sed -i 's/\r//g' /start.sh && exec /bin/bash /start.sh" -``` - -## docker-compose.yml - -```yaml -services: - vrising: - image: trueosiris/vrising - entrypoint: ["/bin/bash", "-c", "sed -i 's/\\r//g' /start.sh && exec /bin/bash /start.sh"] - environment: - - TZ=Europe/Paris - - SERVERNAME=vrising-TrueOsiris2026 - - WINEDEBUG=fixme-all - volumes: - - type: bind - source: ./server - target: /mnt/vrising/server - bind: - create_host_path: true - - type: bind - source: ./persistentdata - target: /mnt/vrising/persistentdata - bind: - create_host_path: true - ports: - - '9876:9876/udp' - - '9877:9877/udp' - restart: unless-stopped - network_mode: bridge -``` - -## Newest modifications: - -- **Intuitive parameters** — If you want to modify parameters in `ServerGameSettings.json` and `ServerHostSettings.json`, add environment variables starting with `GAME_SETTINGS_` and `HOST_SETTINGS_` (both must be uppercase) in your docker-compose.yml file. The parameter names that follow are case-insensitive, so `HOST_SETTINGS_LISTONSTEAM` and `HOST_SETTINGS_ListOnSteam` both work. -```yaml -environment: - - HOST_SETTINGS_ListOnSteam=true - - HOST_SETTINGS_LISTONEOS=true - - GAME_SETTINGS_GAMEMODETYPE=PvE -``` -- **Supports dynamic modification of nested JSON parameters** — since some parameter names contain `_`, a double underscore `__` is used to separate levels. -```yaml -environment: - - HOST_SETTINGS_Rcon__Enabled=true - - HOST_SETTINGS_Rcon__Password=powerfulpwd - - GAME_SETTINGS_UnitStatModifiers_Global__MaxHealthModifier=2 - - GAME_SETTINGS_CastleStatModifiers_Global__HeartLimits__Level1__FloorLimit=100 -``` -- **Fail-safe** — entering a non-existent parameter like `HOST_SETTINGS_NotExistKey=1` will not be written to the configuration file. -- **Parameter type validation** — if the input type differs from the original like `HOST_SETTINGS_Port=abcd`, it will not be written to the configuration file. -- All modified parameter settings can be viewed in: - - `/mnt/vrising/persistentdata/Settings/ServerGameSettings.json` - - `/mnt/vrising/persistentdata/Settings/ServerHostSettings.json` - -## Links - -- [V Rising Dedicated Server Instructions](https://github.com/StunlockStudios/vrising-dedicated-server-instructions) -- [Dockerhub - Trueosiris/vrising](https://hub.docker.com/repository/docker/trueosiris/vrising) -- [Github - trueosiris/vrising](https://github.com/TrueOsiris/docker-vrising) - -## RCON - Optional - -To enable RCON edit `ServerHostSettings.json` and paste following lines after `QueryPort`. To communicate using RCON protocal use the [RCON CLI](https://github.com/gorcon/rcon-cli) by gorcon. - -```json -"Rcon": { - "Enabled": true, - "Password": "docker", - "Port": 25575 -}, -``` +

+ Docker + Ubuntu + Wine +

-## Remarks +

+ Pulls + Stars + GitHub Stars + Last Commit +

-- Server config files are in `/path/on/host/persistentdata/Settings`. Files in `/path/on/host/server/` are overwritten on Steam update.
- Priority of settings is +--- - a. container variables +## Documentation Index - b. files in /persistentdata +Explore our guides to get your server up and running quickly and securely. - c. files in /server. (and these are reset to defaults each new patch) +- 🚀 **[Quick Start & Installation](docs/installation.md)** — Get your server running in minutes using Docker Compose or CLI. +- ⚙️ **[Server Configuration](docs/configuration.md)** — Detailed guide on basic environment variables and advanced dynamic JSON patching. +- 🌐 **[Networking & Ports](docs/networking.md)** — Port forwarding, server list visibility, and custom port configuration. +- 💾 **[Data & Save Management](docs/data-management.md)** — How volumes work, performing backups, and migrating local saves to your server. +- 🔧 **[Troubleshooting](docs/troubleshooting.md)** — Solutions for common errors, Windows host issues, and log explanations. +- 🛠️ **[Development & Contributing](docs/development.md)** — CI/CD pipeline, automated pruning secrets, and the OpenSpec workflow. +- 📜 **[Changelog](CHANGELOG.md)** — Keep track of the latest updates and bug fixes. - If there are no files in `/path/on/host/persistentdata/Settings` on container start, the default files will be copied there from the /server directory.
- Edit `ServerHostSettings.json` if you want to change the ports, descriptions etc. -- Description can be changed in `/path/on/host/persistentdata/Settings/ServerHostSettings.json`. The server will have to be restarted after changes. -- If you use different internal & external ports, you can only use direct connect. For example `-p 12345:6789/udp` container port 6789 as defined in ServerHostSettings.json, and exposed as 12345 will make your server invisible. -- Make sure `"ListOnSteam": true,` and `"ListOnEOS": true` are set in the ServerHostSettings.json in \persistentdata, so the server is visible in the serverlist. -- When the server is passworded, joining via Steam seems not possible. Use the ingame server list to join. -- Launching the server can take up to 10 minutes, even on a fast system, certainly with an existing save. -- If you want to see the server in the server list and want to use 27015-27016/UDP, you'll need to change the ports in the ServerHostSettings.json file to 27015 and 27016. Then expose these ports (below). Of course, forward these udp ports on your firewall from incoming wan to the ports on the internal ip of your dockerhost. +--- - - Start the container & let the server install. - - Stop the container. - - Alter the ports in `/path/on/host/persistentdata/Settings/ServerHostSettings.json` to - ``` - "Port": 27015, - "QueryPort": 27016, - ``` - - On your firewall, port forward incoming wan udp ports 27015 and 27016 to the same udp ports on your dockerhost ip. - - Restart the container with these ports: - ``` - -p 27015:27015/udp - -p 27016:27016/udp - ``` -- If you want to continue from your local game, stop the container, overwrite the persistentdata - contents with your local data, and relaunch the server. - -- If you're running windows as a docker host, you'll get this exception: - ``` - vrising-1 | 0024:err:module:LdrInitializeThunk "UnityPlayer.dll" failed to initialize, aborting - vrising-1 | 0024:err:module:LdrInitializeThunk Initializing dlls for L"Z:\\mnt\\vrising\\server\\VRisingServer.exe" failed, status c0000005 - ``` - Unless you use volumes like this: - ``` - volumes: - - E:\something\server:/mnt/vrising/server - ``` -- You might want to add a separate custom settings file (Custom.json) in persistentdata. - - start the server to have the files created - - shut down the server - - add custom.json to the persistentdata folder (see volumes) - - Then point your ServerHostSettings in persistentdata/Settings to that file by adding `"GameSettingsPreset": "Custom"` - - start the server again. +## Quick Features -## Docker log +- **Automated Updates**: SteamCMD integration ensures your server is always running the latest version. +- **Dynamic Configuration**: Modify game and host settings directly from your `docker-compose.yml` without touching JSON files. +- **Slim & Fast**: Optimized Ubuntu 24.04 base with Wine 11.0 for maximum compatibility and performance. +- **Verified Stability**: Includes automated E2E testing to ensure the image always boots successfully. -Since 1.1 the log will be spamming these messages, but no need to worry:
-vrising-1 | 01b4:fixme:winsock:server_ioctl_sock Unsupported ioctl 4004747b (device=4004 access=1 func=d1e method=3)
-vrising-1 | 01b4:fixme:winsock:WSAIoctl unsupported WS_IOCTL cmd (SIO_IDEAL_SEND_BACKLOG_QUERY)
+--- -Here is a [working 1.1.hotfix3 log](https://github.com/TrueOsiris/docker-vrising/blob/main/logs/1.1.hotfix3.log) as reference. +## Credits & Links -## Credits +- [Official V Rising Website](https://playvrising.com/) +- [V Rising Dedicated Server Instructions (Stunlock Studios)](https://github.com/StunlockStudios/vrising-dedicated-server-instructions) +- [Docker Hub Page](https://hub.docker.com/r/trueosiris/vrising) -- All credits go to the awesome designers of [V-Rising](https://playvrising.com/)! +*Special thanks to the Stunlock Studios team for creating such an amazing game!* diff --git a/docker-compose.test.yml b/docker-compose.test.yml new file mode 100644 index 0000000..a4ecd0f --- /dev/null +++ b/docker-compose.test.yml @@ -0,0 +1,26 @@ +services: + vrising: + build: + context: . + platform: linux/amd64 + image: vrising-test + environment: + - TZ=Europe/Rome + - SERVERNAME=vrising-dedicated + - WINEDEBUG=fixme-all + - PUID=1000 + - PGID=1000 + volumes: + - ./test_server:/mnt/vrising/server + - ./test_data:/mnt/vrising/persistentdata + ports: + - '9876:9876/udp' + - '9877:9877/udp' + healthcheck: + test: ["CMD-SHELL", "nc -z -u 127.0.0.1 $${QUERYPORT:-9877} || exit 1"] + interval: 10s # Faster for tests + timeout: 5s + start_period: 30s # Shorter for tests? No, Wine still needs time. Let's keep it somewhat realistic. + retries: 5 + restart: unless-stopped + network_mode: bridge diff --git a/docker-compose.yml b/docker-compose.yml index 3050403..9165eb4 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,11 +1,12 @@ services: vrising: image: trueosiris/vrising - entrypoint: ["/bin/bash", "-c", "sed -i 's/\\r//g' /start.sh && exec /bin/bash /start.sh"] environment: - - TZ=Europe/Paris - - SERVERNAME=vrising-TrueOsiris2026 + - TZ=Europe/Rome + - SERVERNAME=vrising-dedicated - WINEDEBUG=fixme-all + - PUID=1000 + - PGID=1000 volumes: - type: bind source: /your/host/vrising/server @@ -20,5 +21,11 @@ services: ports: - '9876:9876/udp' - '9877:9877/udp' + healthcheck: + test: ["CMD-SHELL", "nc -z -u 127.0.0.1 $${QUERYPORT:-9877} || exit 1"] + interval: 30s + timeout: 10s + start_period: 120s + retries: 3 restart: unless-stopped network_mode: bridge diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 0000000..2b16461 --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,175 @@ +# Server Configuration + +The V Rising Docker image provides three ways to configure your server: environment variables, dynamic JSON patching, and direct file editing. + +## 1. Core Environment Variables + +These variables control the basic identity and networking of your server. + +| Variable | Default | Description | +| :--- | :--- | :--- | +| `TZ` | `Europe/Rome` | Timezone for the server logs and scheduling. | +| `SERVERNAME` | `vrising-dedicated` | The name of your server as it appears in the server list. | +| `WORLDNAME` | `world1` | The name of the world save file. | +| `GAMEPORT` | `9876` | The UDP port for game traffic. | +| `QUERYPORT` | `9877` | The UDP port for Steam query traffic. | +| `LOGDAYS` | `30` | Number of days to keep server logs before automatic cleanup. | +| `BRANCH` | `(latest)` | Optional: Use `legacy-1.0.x-pc` to run an older version. | + +## 2. Dynamic JSON Configuration (Recommended) + +You can modify almost any setting in `ServerGameSettings.json` and `ServerHostSettings.json` directly from your `docker-compose.yml` or Docker CLI using environment variable prefixes. + +### Basic Usage +- Use `GAME_SETTINGS_` to patch `ServerGameSettings.json` +- Use `HOST_SETTINGS_` to patch `ServerHostSettings.json` + +Example: +```yaml +environment: + - HOST_SETTINGS_ListOnSteam=true + - HOST_SETTINGS_ListOnEOS=true + - GAME_SETTINGS_GameModeType=PvE +``` + +### Nested Parameters +V Rising settings are often nested. Use a double underscore (`__`) to navigate through JSON levels. + +Example: +```yaml +environment: + - HOST_SETTINGS_Rcon__Enabled=true + - HOST_SETTINGS_Rcon__Password=mypassword + - GAME_SETTINGS_UnitStatModifiers_Global__MaxHealthModifier=2 + - GAME_SETTINGS_CastleStatModifiers_Global__HeartLimits__Level1__FloorLimit=100 +``` + +### Features +- **Case-Insensitive**: Both `HOST_SETTINGS_ListOnSteam` and `HOST_SETTINGS_LISTONSTEAM` work. +- **Fail-Safe**: If you provide a setting that doesn't exist, it will be ignored. +- **Type Validation**: If a setting expects a number and you provide a string, the update will be skipped to prevent corruption. + +## 3. Direct File Editing + +You can also edit the JSON files directly on your host machine. They are located in your persistent data directory: +- `/mnt/vrising/persistentdata/Settings/ServerGameSettings.json` +- `/mnt/vrising/persistentdata/Settings/ServerHostSettings.json` + +**Priority of Settings:** +1. Dynamic Environment Variables (`GAME_SETTINGS_*`) +2. Local files in `/persistentdata` +3. Default files in `/server` (reset on every Steam update) + +## 📁 Understanding Your Data + +When you run the Docker container, it creates folders on your host machine to store game files and your personal data. + +```text +Your Host Machine (Local) Docker Container (Internal) +┌─────────────────────────┐ ┌─────────────────────────┐ +│ ./server/ │ ───────▶ │ /mnt/vrising/server/ │ (Game Binaries - Automated) +├─────────────────────────┤ ├─────────────────────────┤ +│ ./persistentdata/ │ ───────▶ │ /mnt/.../persistentdata/│ (YOUR DATA - BACK THIS UP!) +│ ├── Settings/ │ │ │ +│ │ ├── adminlist.txt │ │ │ +│ │ └── *.json │ │ │ +│ └── Saves/ │ │ │ +│ └── v3/world1/ │ │ │ +└─────────────────────────┘ └─────────────────────────┘ +``` + +**Note:** Never modify files in the `./server` folder manually. All configuration and saves live in `./persistentdata`. + +## 👑 Admins & Bans + +To manage players on your server, you use the `adminlist.txt` and `banlist.txt` files located in your host's `./persistentdata/Settings/` directory. + +### Adding Admins +1. Navigate to `./persistentdata/Settings/` on your host. +2. Create or edit `adminlist.txt`. +3. Add the **Steam64 IDs** (one per line). Use a tool like [steamid.io](https://steamid.io) to find them. +4. Restart the container. +5. In-game, open the console (`~`) and type `adminauth`. + +### Banning Players +1. Navigate to `./persistentdata/Settings/` on your host. +2. Create or edit `banlist.txt`. +3. Add the **Steam64 IDs** of the players you wish to ban. +4. Restart the container. + +## 🩺 Container Healthcheck + +The V Rising dedicated server under Wine can take several minutes to generate a new world or load a large save file. To reliably determine when the server is fully ready to accept connections, the Docker image includes a native `HEALTHCHECK`. + +The healthcheck performs a UDP ping against the server's Query Port (`QUERYPORT`). + +By default, the healthcheck is configured with a generous `start_period` of 120 seconds to account for the initial load time without prematurely marking the container as unhealthy. This is particularly useful for orchestrating other containers (like an RCON sidecar) that should only start once the server is fully initialized. + +## 📡 RCON (Remote Console) + +RCON allows you to send commands to your server without being in-game. + +### Enabling RCON (Recommended Method) +Add these environment variables to your `docker-compose.yml`: + +```yaml +environment: + - HOST_SETTINGS_Rcon__Enabled=true + - HOST_SETTINGS_Rcon__Password=SuperSecretPassword + - HOST_SETTINGS_Rcon__Port=25575 +ports: + - '25575:25575/tcp' # Ensure you expose the TCP port! +``` + +### Executing Commands (Standalone) +You don't need to install anything on your host. Use a temporary Docker container to run the [gorcon/rcon-cli](https://github.com/gorcon/rcon-cli): + +```bash +docker run --rm gorcon/rcon-cli -a 127.0.0.1:25575 -p SuperSecretPassword "announce 'Server is restarting in 5 minutes!'" +``` + +### Running an RCON Sidecar (Docker Compose) +If you prefer to have an RCON client running continuously alongside your server, you can configure an RCON sidecar in your `docker-compose.yml`. This sidecar will automatically wait for the V Rising server to become `healthy` before starting. + +```yaml +services: + vrising: + image: trueosiris/vrising + environment: + - SERVERNAME=My RCON Server + - HOST_SETTINGS_Rcon__Enabled=true + - HOST_SETTINGS_Rcon__Password=SuperSecretPassword + ports: + - '9876:9876/udp' + - '9877:9877/udp' + - '25575:25575/tcp' + healthcheck: + test: ["CMD-SHELL", "nc -z -u 127.0.0.1 $${QUERYPORT:-9877} || exit 1"] + interval: 30s + timeout: 10s + start_period: 120s + retries: 3 + + rcon: + image: itzg/rcon-cli:latest + environment: + - RCON_HOST=vrising + - RCON_PORT=25575 + - RCON_PASSWORD=SuperSecretPassword + depends_on: + vrising: + condition: service_healthy +``` +You can then easily execute commands through the sidecar container: +```bash +docker compose exec rcon rcon-cli "announce 'Hello World!'" +``` + +### Useful Commands +| Command | Description | +| :--- | :--- | +| `announce ` | Send a global message to all players. | +| `kick ` | Kick a player from the server. | +| `banuser ` | Ban a player from the server. | +| `unban ` | Unban a player. | +| `save` | Force an immediate world save. | diff --git a/docs/data-management.md b/docs/data-management.md new file mode 100644 index 0000000..a6ab8f8 --- /dev/null +++ b/docs/data-management.md @@ -0,0 +1,51 @@ +# Data & Save Management + +This document explains how your server data is stored and how to manage your game saves. + +## Volumes & Persistence + +To ensure your server data survives a container restart, you must map the following volumes to your host machine: + +| Host Path | Container Path | Description | +| :--- | :--- | :--- | +| `./server` | `/mnt/vrising/server` | Installation files for the dedicated server (from Steam). | +| `./persistentdata` | `/mnt/vrising/persistentdata` | Your world saves, settings, and logs. | + +### Storage Tips +- **Disk Space**: The initial server download takes several GB. Ensure your host machine has sufficient space. +- **Backups**: We recommend backing up your `persistentdata/Saves` directory regularly. + +## 🕒 Automated Backups (Linux) + +You can use a simple `cron` job on your host machine to automate backups of your world saves. + +1. Open your host's crontab: + ```bash + crontab -e + ``` +2. Add the following line to create a compressed backup at 3:00 AM every day: + ```bash + 0 3 * * * tar -czf /path/to/your/backups/vrising_$(date +\%Y\%m\%d).tar.gz /path/to/your/persistentdata/Saves >/dev/null 2>&1 + ``` +*Replace `/path/to/your/backups` and `/path/to/your/persistentdata` with your actual absolute paths.* + +## Migrating a Local Save + +If you want to move a save from your local PC to your dedicated server: + +1. **Locate Local Save**: Find your save files on your local machine (typically in `%AppData%\LocalLow\Stunlock Studios\VRising\Saves`). +2. **Stop Server**: Stop your Docker container. +3. **Copy Files**: Overwrite the contents of the `persistentdata/Saves` directory on your Docker host with your local save data. +4. **Restart Server**: Relaunch the container. + +## Using a Custom Settings Preset + +If you have a `Custom.json` configuration file: +1. Start the server once to generate the directory structure. +2. Stop the server. +3. Place your `Custom.json` into the `persistentdata` folder. +4. In your `ServerHostSettings.json`, update the following line: + ```json + "GameSettingsPreset": "Custom" + ``` +5. Restart the server. diff --git a/docs/development.md b/docs/development.md new file mode 100644 index 0000000..c38d333 --- /dev/null +++ b/docs/development.md @@ -0,0 +1,86 @@ +# Development & Contribution Guide + +Welcome! If you're looking to contribute or understand how this project operates under the hood, this guide is for you. + +## 📦 CI/CD Pipeline & Releases + +The build and deployment process is fully automated using GitHub Actions. + +### The `docker-image.yml` Pipeline +Every push to the `main` branch triggers the primary workflow, which consists of three jobs: +1. **Build:** Compiles the Docker image and pushes a temporary staging tag (using the commit SHA) to the GitHub Container Registry (GHCR). +2. **Test:** Pulls the staging image from GHCR and runs end-to-end tests (`scripts/test-startup.sh`) to ensure the server starts correctly. +3. **Publish (Only on Release):** If the workflow was triggered by a Git semantic version tag (e.g., `v1.0.0`), the tested image is pulled, tagged with the release version and `latest`, and pushed to Docker Hub for public consumption. + +### How to Release +To release a new version of the image to Docker Hub: +1. Ensure all changes are merged into `main` and tests pass. +2. Create and push a new Git tag: + ```bash + git tag v1.x.x + git push origin v1.x.x + ``` +3. The pipeline will automatically build, test, and publish the tagged image. + +## 🧹 Maintenance: Automated Pruning + +To keep our registries clean, we use a scheduled workflow (`.github/workflows/prune-registries.yml`) that runs every Sunday. + +### What it does: +- **GHCR:** Deletes any untagged images (which accumulate when staging tags are overwritten). +- **Docker Hub:** Runs an API script to delete old, commit-SHA tagged images, preserving only `latest` and semantic version tags (`vX.X.X`). + +### ⚠️ Required Secrets +For the automated registry pruning to work, repository secrets must be properly configured: +- **`PAT_WITH_DELETE_PACKAGES_SCOPE`**: A GitHub Personal Access Token created by an admin with the `delete:packages` scope. The default `GITHUB_TOKEN` does not have permission to delete packages from GHCR. +- **`DOCKERHUB_TOKEN`**: A Docker Hub Personal Access Token. This token MUST be created with **Read, Write, and Delete** permissions. If it lacks delete permissions, the script will receive a `403 Forbidden` error when attempting to prune old staging tags. + +--- + +## 🤖 Automated Dependency Updates + +This project uses custom GitHub Actions to automatically track and propose updates for critical dependencies. + +- **Wine (`.github/workflows/update-wine.yml`)**: Runs monthly. It queries the Ubuntu Noble WineHQ repository for the latest `winehq-stable` version and proposes a PR to update the `WINE_VERSION` in the `Dockerfile`. +- **V Rising (`.github/workflows/update-vrising.yml`)**: Runs weekly. It queries the SteamCMD Web API for the latest `buildid` of the V Rising Dedicated Server and proposes a PR to update the `VRISING_BUILD_ID` in the `Dockerfile`. + +These automated PRs ensure the Docker image stays up-to-date with upstream changes without manual tracking. Merging these PRs will automatically trigger the standard `docker-image.yml` build pipeline. + +--- + +## 🏗️ OpenSpec Artifact-Driven Workflow + +This project uses **OpenSpec**, an experimental artifact-driven workflow, to manage significant changes. This ensures every change is deliberately proposed, designed, and specified before any code is written. + +### Why OpenSpec? +OpenSpec creates a paper trail for the *intent* and *rationale* behind code changes. It breaks down complex ideas into manageable, trackable artifacts. + +### The Process + +1. **Start a New Change:** + Use the Gemini CLI (or OpenSpec directly) to initialize a new change directory. + ```bash + /opsx:new add-new-feature + ``` + This creates a folder in `openspec/changes/add-new-feature/`. + +2. **Artifact Sequence:** + You will be guided to create a series of Markdown documents: + - **`proposal.md`**: *Why* are we doing this? What capabilities are affected? + - **`design.md`**: *How* are we going to build it technically? (Decisions, Trade-offs) + - **`specs//spec.md`**: *What* exactly must it do? (Formal requirements and testable scenarios) + - **`tasks.md`**: A trackable checklist of implementation steps. + +3. **Implementation:** + Once all artifacts are approved, the actual coding begins, using `tasks.md` as the source of truth. + ```bash + /opsx:apply + ``` + +4. **Archive:** + When the code is merged and tasks are complete, the change is archived. If any specs were modified, they are automatically synced to the main `openspec/specs/` directory, acting as living documentation for the project. + ```bash + /opsx:archive + ``` + +If you are proposing a significant architecture shift or new feature, please draft a change proposal via OpenSpec! diff --git a/docs/docker-hub-description.md b/docs/docker-hub-description.md new file mode 100644 index 0000000..07ade86 --- /dev/null +++ b/docs/docker-hub-description.md @@ -0,0 +1,126 @@ +# 🧛 V Rising Dedicated Server (Docker) + +[![Docker Pulls](https://img.shields.io/docker/pulls/trueosiris/vrising?logo=docker&label=pulls)](https://hub.docker.com/r/trueosiris/vrising) +[![Docker Stars](https://img.shields.io/docker/stars/trueosiris/vrising?logo=docker&label=stars)](https://hub.docker.com/r/trueosiris/vrising) +[![GitHub Stars](https://img.shields.io/github/stars/TrueOsiris/docker-vrising?logo=github&label=stars)](https://github.com/TrueOsiris/docker-vrising) +[![Ubuntu 24.04](https://img.shields.io/badge/Ubuntu-24.04-E95420?logo=ubuntu&logoColor=white)](https://ubuntu.com) +[![Wine 11.0](https://img.shields.io/badge/Wine-11.0-800000?logo=wine&logoColor=white)](https://winehq.org) + +A high-performance, easy-to-use Dockerized V Rising dedicated server running on **Ubuntu 24.04** with **Wine 11.0**. Designed for stability, ease of configuration, and automated maintenance. + +--- + +## 🚀 Quick Start (Docker Compose) + +The recommended way to run the server is using [Docker Compose](https://docs.docker.com/compose/). Create a `docker-compose.yml` file and paste the following: + +```yaml +services: + vrising: + image: trueosiris/vrising + container_name: vrising-server + environment: + - TZ=Europe/Rome + - SERVERNAME=vrising-dedicated + - WORLDNAME=world1 + volumes: + - ./server:/mnt/vrising/server # Game binaries (automated update) + - ./persistentdata:/mnt/vrising/persistentdata # YOUR SAVES & SETTINGS + ports: + - '9876:9876/udp' # Game Port + - '9877:9877/udp' # Query Port + healthcheck: + test: ["CMD-SHELL", "nc -z -u 127.0.0.1 $${QUERYPORT:-9877} || exit 1"] + interval: 30s + timeout: 10s + start_period: 120s + retries: 3 + restart: unless-stopped +``` + +Then run: +```bash +docker compose up -d +``` + +--- + +## ✨ Features + +* **Automated Updates:** Built-in SteamCMD integration ensures your server is always up-to-date on every restart. +* **Dynamic JSON Patching:** Modify `ServerGameSettings.json` and `ServerHostSettings.json` directly via environment variables (no manual JSON editing required!). +* **Native Healthcheck:** Reliable readiness reporting via UDP query port pinging. +* **Optimized Stack:** Built on Ubuntu 24.04 with the latest stable Wine 11.0 for maximum performance. +* **Slim Image:** Automated pruning of build-time dependencies to keep the image footprint small. + +--- + +## ⚙️ Configuration + +### Core Environment Variables +| Variable | Default | Description | +| :--- | :--- | :--- | +| `SERVERNAME` | `vrising-dedicated` | Your server's name in the server list. | +| `WORLDNAME` | `world1` | The name of your world save file. | +| `TZ` | `Europe/Rome` | Timezone for logs and scheduling. | +| `PUID` / `PGID` | `1000` | User/Group ID for file permissions. | + +### Dynamic JSON Configuration (Advanced) +Patch any setting in the internal JSON files using these prefixes: +* `GAME_SETTINGS_` for `ServerGameSettings.json` +* `HOST_SETTINGS_` for `ServerHostSettings.json` + +**Example:** +```yaml +environment: + - HOST_SETTINGS_ListOnSteam=true + - HOST_SETTINGS_Rcon__Enabled=true + - HOST_SETTINGS_Rcon__Password=MySecretPassword + - GAME_SETTINGS_GameModeType=PvE + - GAME_SETTINGS_UnitStatModifiers_Global__MaxHealthModifier=2 +``` + +--- + +## 📡 RCON & Sidecars + +This image supports a persistent RCON sidecar pattern. You can run an RCON client that waits for the server to be `healthy` before starting: + +```yaml +services: + vrising: + # ... (see Quick Start) + environment: + - HOST_SETTINGS_Rcon__Enabled=true + - HOST_SETTINGS_Rcon__Password=SuperSecretPassword + + rcon: + image: outdead/rcon-cli:latest + environment: + - RCON_HOST=vrising + - RCON_PORT=25575 + - RCON_PASSWORD=SuperSecretPassword + depends_on: + vrising: + condition: service_healthy +``` + +--- + +## 📖 Full Documentation + +For detailed guides on networking, data management, and troubleshooting, visit the official repository: + +🔗 **[GitHub Repository: TrueOsiris/docker-vrising](https://github.com/TrueOsiris/docker-vrising)** + +* [🚀 Installation Guide](https://github.com/TrueOsiris/docker-vrising/blob/main/docs/installation.md) +* [⚙️ Detailed Configuration](https://github.com/TrueOsiris/docker-vrising/blob/main/docs/configuration.md) +* [💾 Data & Saves](https://github.com/TrueOsiris/docker-vrising/blob/main/docs/data-management.md) +* [🌐 Networking & Ports](https://github.com/TrueOsiris/docker-vrising/blob/main/docs/networking.md) + +--- + +## ❤️ Credits & Thanks +* **[TrueOsiris](https://github.com/TrueOsiris)**: A special thank you to the original creator of this project for their incredible foundational work and contributions to the V Rising Docker community. +* **Stunlock Studios**: For creating such a fantastic game! +* **Community Contributors**: For the ongoing bug reports, fixes, and feature suggestions. diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 0000000..32132e9 --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,121 @@ +# Installation + +This guide covers how to set up and run the V Rising dedicated server using Docker. + +## Quick Start (Docker Compose) + +The recommended way to run the server is using [Docker Compose](https://docs.docker.com/compose/). + +```yaml +services: + vrising: + image: trueosiris/vrising + environment: + - TZ=Europe/Rome + - SERVERNAME=vrising-dedicated + volumes: + - ./server:/mnt/vrising/server + - ./persistentdata:/mnt/vrising/persistentdata + ports: + - '9876:9876/udp' + - '9877:9877/udp' + healthcheck: + test: ["CMD-SHELL", "nc -z -u 127.0.0.1 $${QUERYPORT:-9877} || exit 1"] + interval: 30s + timeout: 10s + start_period: 120s + retries: 3 + restart: unless-stopped +``` + +### Starting the server +```bash +docker-compose up -d +``` + +## 🎮 Configuration Sets (Recipes) + +Not sure what settings to use? Pick the `docker-compose.yml` that best fits how you want to play. These examples use the default V Rising ports (27015/27016) which are common in community guides. + +### Option A: Standard PvE (Co-op with Friends) +Perfect for a private server where you work together to build a castle and defeat bosses. + +```yaml +services: + vrising: + image: trueosiris/vrising + environment: + - SERVERNAME="My Cozy Vampire Castle" + - WORLDNAME="world1" + # Secure the server so only friends can join + - HOST_SETTINGS_Password=secretblood + # Set to PvE (Player vs Environment) + - GAME_SETTINGS_GameModeType=PvE + # Quality of Life: Allow teleporting with resources + - GAME_SETTINGS_TeleportBoundItems=false + volumes: + - ./server:/mnt/vrising/server + - ./persistentdata:/mnt/vrising/persistentdata + ports: + - '27015:27015/udp' # Game Port + - '27016:27016/udp' # Query Port + healthcheck: + test: ["CMD-SHELL", "nc -z -u 127.0.0.1 $${QUERYPORT:-27016} || exit 1"] + interval: 30s + timeout: 10s + start_period: 120s + retries: 3 + restart: unless-stopped +``` + +### Option B: Standard PvP (Competitive) +A public server focused on clan warfare and raiding. + +```yaml +services: + vrising: + image: trueosiris/vrising + environment: + - SERVERNAME="Blood & Glory [PvP]" + - WORLDNAME="pvp_world1" + # Ensure it shows up on the public server list + - HOST_SETTINGS_ListOnSteam=true + - HOST_SETTINGS_ListOnEOS=true + # Use the official Standard PvP preset + - GAME_SETTINGS_Preset=StandardPvP + volumes: + - ./server:/mnt/vrising/server + - ./persistentdata:/mnt/vrising/persistentdata + ports: + - '27015:27015/udp' + - '27016:27016/udp' + healthcheck: + test: ["CMD-SHELL", "nc -z -u 127.0.0.1 $${QUERYPORT:-27016} || exit 1"] + interval: 30s + timeout: 10s + start_period: 120s + retries: 3 + restart: unless-stopped +``` + +## Docker CLI + +If you prefer using the Docker CLI directly: + +```bash +docker run -d --name='vrising' \ + --restart=unless-stopped \ + -e TZ="Europe/Rome" \ + -e SERVERNAME="vrising-dedicated" \ + -v "$(pwd)/server:/mnt/vrising/server" \ + -v "$(pwd)/persistentdata:/mnt/vrising/persistentdata" \ + -p 9876:9876/udp \ + -p 9877:9877/udp \ + trueosiris/vrising +``` + +## Post-Installation + +- Launching the server can take up to 10 minutes, especially on the first run or with an existing save. +- Once the server is running, you can find your configuration files in your host's `persistentdata/Settings` folder. +- For networking and port forwarding details, see [Networking & Ports](networking.md). diff --git a/docs/networking.md b/docs/networking.md new file mode 100644 index 0000000..d46c568 --- /dev/null +++ b/docs/networking.md @@ -0,0 +1,53 @@ +# Networking & Ports + +Stable networking is crucial for your V Rising dedicated server to be visible and joinable. + +## Default Ports + +The container exposes two primary UDP ports: + +| Container Port | Protocol | Usage | +| :--- | :--- | :--- | +| `9876` | UDP | Game Traffic (Joining the server) | +| `9877` | UDP | Steam Query Traffic (Server list visibility) | + +## Port Forwarding (WAN) + +To allow players outside your local network to join, you MUST forward the game and query ports on your router to the internal IP address of your Docker host. + +- **Requirement**: Use the same internal and external port numbers whenever possible. +- **Example**: Forward WAN `9876/UDP` to Docker Host `9876/UDP`. + +## Server List Visibility + +To ensure your server appears in the in-game server list: + +1. Ensure both `9876/UDP` and `9877/UDP` are correctly forwarded. +2. In your `ServerHostSettings.json` (or via dynamic env vars), set: + - `"ListOnSteam": true` + - `"ListOnEOS": true` + +## Custom Ports (Advanced) + +If you want to use non-standard ports (e.g., `27015/UDP` and `27016/UDP`): + +1. **Update Configuration**: Alter the ports in `/mnt/vrising/persistentdata/Settings/ServerHostSettings.json`: + ```json + { + "Port": 27015, + "QueryPort": 27016 + } + ``` +2. **Update Docker Mapping**: Restart your container with the new ports mapped 1:1: + ```yaml + ports: + - '27015:27015/udp' + - '27016:27016/udp' + ``` + +> **Warning**: If you use different internal and external ports (e.g., `-p 12345:6789/udp`), the server will become invisible in the server list, and players will only be able to join via **Direct Connect**. + +## Connectivity Issues + +- **Passwords**: joining via Steam can be unreliable when the server is password-protected. We recommend using the **in-game server list** to join. +- **Firewalls**: Ensure your host's software firewall (e.g., `ufw`, `iptables`, Windows Firewall) is not blocking the UDP traffic. diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md new file mode 100644 index 0000000..7231c79 --- /dev/null +++ b/docs/troubleshooting.md @@ -0,0 +1,68 @@ +# Troubleshooting + +Common issues and solutions for running the V Rising dedicated server in Docker. + +## Common Log Messages (Harmless) + +Since version 1.1, the logs may frequently display messages like these. You can safely ignore them: + +```text +01b4:fixme:winsock:server_ioctl_sock Unsupported ioctl 4004747b (device=4004 access=1 func=d1e method=3) +01b4:fixme:winsock:WSAIoctl unsupported WS_IOCTL cmd (SIO_IDEAL_SEND_BACKLOG_QUERY) +``` + +## 🛑 Server Not Showing in the Public List + +This is the most common issue. If your server is running but you (or your friends) can't see it in the in-game list: + +1. **Verify Ports:** Ensure both the Game Port (`27015 UDP`) and the Query Port (`27016 UDP`) are open and forwarded on your router to the internal IP of the machine running Docker. **Both must be UDP.** +2. **Host Firewall:** Check that the firewall on your host machine (e.g., Windows Defender, ufw, firewalld) is allowing UDP traffic on those ports. +3. **List Settings:** Verify your configuration has `HOST_SETTINGS_ListOnSteam=true` and `HOST_SETTINGS_ListOnEOS=true`. +4. **Direct Connect:** Try using the "Direct Connect" button in-game and entering `YOUR_EXTERNAL_IP:27015`. If this works but the list doesn't, your Query Port (`27016`) is likely blocked. + +## 💾 Save Corruption & Rollbacks + +If your server crashes during a save or power loss, your world might become corrupted. The game automatically keeps a history of auto-saves using the `AutoSaveSmartKeep` system. + +**How to roll back your server:** +1. **Stop the server:** `docker-compose down` +2. Navigate to your saves folder: `./persistentdata/Saves/v3/YOUR_WORLD_NAME/` +3. You will see several folders with timestamps (e.g., `AutoSave_20240101_120000`). The game loads the folder named `AutoSave_Latest`. +4. Delete (or move) the `AutoSave_Latest` folder. +5. Find the most recent timestamped folder that you know was working, and **rename it to** `AutoSave_Latest`. +6. **Start the server:** `docker-compose up -d` + +## 🧩 Modding Support (BepInEx) + +This Docker image provides the **vanilla** V Rising dedicated server. It does not automatically install mod frameworks or plugins. + +**How to mod this server:** +- To use mods, you must manually install the **BepInEx** framework into your mapped `./server` volume on the host. +- Most mods involve placing `.dll` files into a `BepInEx/plugins` folder that you create inside the server directory. +- **Note:** Modding may cause stability issues and is not officially supported by this project. + +## Windows Docker Host Issues + +If you are running Docker on a Windows host and encounter the following exception: + +```text +vrising-1 | 0024:err:module:LdrInitializeThunk "UnityPlayer.dll" failed to initialize, aborting +vrising-1 | 0024:err:module:LdrInitializeThunk Initializing dlls for L"Z:\\mnt\\vrising\\server\\VRisingServer.exe" failed, status c0000005 +``` + +**Solution**: You must use absolute paths for your volume mappings. Example: + +```yaml +volumes: + - E:\\my-server-folder\\server:/mnt/vrising/server +``` + +## Performance & Startup + +- **Long Startup Times**: Depending on your hardware and network, the server can take up to **10 minutes** to fully initialize, especially when downloading updates or loading large save files. +- **CPU Requirements**: The server requires a modern CPU. If your CPU does not support AVX/AVX2, some plugins like `lib_burst_generated.dll` might cause crashes. The container includes a fix to disable these plugins if AVX is missing. + +## Getting Help + +- [V Rising Official Instructions](https://github.com/StunlockStudios/vrising-dedicated-server-instructions) +- [Project GitHub Issues](https://github.com/TrueOsiris/docker-vrising/issues) diff --git a/scripts/test-startup.sh b/scripts/test-startup.sh new file mode 100755 index 0000000..d51063d --- /dev/null +++ b/scripts/test-startup.sh @@ -0,0 +1,73 @@ +#!/bin/bash +set -e + +# Configuration +IMAGE_NAME=${1:-"vrising-e2e-test"} +CONTAINER_NAME="vrising-test-run-$(date +%s)" +TIMEOUT_SECONDS=600 # 10 minutes +CHECK_INTERVAL=10 +SUCCESS_STRING="Startup Completed" + +# Cleanup function +cleanup() { + echo "Cleaning up..." + docker stop "$CONTAINER_NAME" >/dev/null 2>&1 || true + docker rm -f "$CONTAINER_NAME" >/dev/null 2>&1 || true + if [ -d "$TEST_DIR" ]; then + # Use a temporary docker container to run rm -rf as root on the CONTENTS of the directory + # bypassing permission issues from files owned by the 'steam' user + docker run --rm -v "$TEST_DIR:/test_dir" ubuntu:24.04 bash -c "rm -rf /test_dir/* /test_dir/.* 2>/dev/null || true" + rm -rf "$TEST_DIR" + fi +} + +# Ensure cleanup on exit +trap cleanup EXIT + +if [ -z "$1" ]; then + echo "No image name provided. Building Docker image locally..." + docker build -t "$IMAGE_NAME" . +else + echo "Using provided image: $IMAGE_NAME" +fi + +echo "Creating temporary data directory..." +TEST_DIR=$(mktemp -d) +chmod 777 "$TEST_DIR" + +echo "Starting container..." +docker run -d \ + --name "$CONTAINER_NAME" \ + -v "$TEST_DIR:/mnt/vrising" \ + "$IMAGE_NAME" + +echo "Waiting for server to start (Timeout: ${TIMEOUT_SECONDS}s)..." +START_TIME=$(date +%s) +while true; do + CURRENT_TIME=$(date +%s) + ELAPSED=$((CURRENT_TIME - START_TIME)) + + if [ "$ELAPSED" -gt "$TIMEOUT_SECONDS" ]; then + echo "Error: Timeout waiting for server to start after ${TIMEOUT_SECONDS} seconds." + docker logs "$CONTAINER_NAME" | tail -n 20 + exit 1 + fi + + if docker logs "$CONTAINER_NAME" 2>&1 | grep -q "$SUCCESS_STRING"; then + echo "Success: Server started successfully!" + break + fi + + # Check if container is still running + if ! docker ps -q --no-trunc | grep -q "^$(docker inspect -f '{{.Id}}' "$CONTAINER_NAME")"; then + echo "Error: Container stopped unexpectedly." + docker logs "$CONTAINER_NAME" + exit 1 + fi + + echo "Still waiting... (${ELAPSED}s elapsed)" + sleep "$CHECK_INTERVAL" +done + +echo "Test passed!" +exit 0 diff --git a/start.sh b/start.sh index 50d61fd..73c3597 100644 --- a/start.sh +++ b/start.sh @@ -1,7 +1,34 @@ #!/bin/bash + +# Configuration paths s=/mnt/vrising/server p=/mnt/vrising/persistentdata +# --- PRE-START (Root Operations) --- +if [ "$(id -u)" = '0' ]; then + echo "Running as root, setting up permissions..." + + # Support for PUID/PGID + PUID=${PUID:-1000} + PGID=${PGID:-1000} + + echo "Ensuring steam user matches PUID:PGID ($PUID:$PGID)" + groupmod -o -g "$PGID" steam + usermod -o -u "$PUID" steam + + # Ensure directories exist and are owned by steam + mkdir -p "$s" "$p" "/home/steam/.steam" + chown -R steam:steam "$s" "$p" "/home/steam" + + # Fix for Xvfb lock if it exists + rm -f /tmp/.X0-lock + + echo "Switching to steam user and continuing..." + exec gosu steam "$0" "$@" +fi + +# --- RUNTIME (Steam User Operations) --- + term_handler() { echo "Shutting down Server" @@ -19,33 +46,31 @@ term_handler() { cleanup_logs() { echo "Cleaning up logs older than $LOGDAYS days" - find "$p" -name "*.log" -type f -mtime +$LOGDAYS -exec rm {} \; + find "$p" -name "*.log" -type f -mtime +"$LOGDAYS" -exec rm {} \; } trap 'term_handler' SIGTERM -if [ -z "$LOGDAYS" ]; then - LOGDAYS=30 -fi -if [[ -n $UID ]]; then - usermod -u "$UID" docker 2>&1 -fi -if [[ -n $GID ]]; then - groupmod -g "$GID" docker 2>&1 -fi -if [ -z "$SERVERNAME" ]; then - SERVERNAME="trueosiris-V" -fi +# Default Environment Variables +LOGDAYS=${LOGDAYS:-30} +SERVERNAME=${SERVERNAME:-"vrising-dedicated"} +WORLDNAME=${WORLDNAME:-""} +GAMEPORT=${GAMEPORT:-""} +QUERYPORT=${QUERYPORT:-""} +BRANCH=${BRANCH:-""} + override_savename="" if [[ -n "$WORLDNAME" ]]; then override_savename="-saveName $WORLDNAME" fi + game_port="" -if [[ -n $GAMEPORT ]]; then +if [[ -n "$GAMEPORT" ]]; then game_port=" -gamePort $GAMEPORT" fi + query_port="" -if [[ -n $QUERYPORT ]]; then +if [[ -n "$QUERYPORT" ]]; then query_port=" -queryPort $QUERYPORT" fi @@ -53,16 +78,26 @@ beta_arg="" if [ -n "$BRANCH" ]; then beta_arg=" -beta $BRANCH" fi + cleanup_logs -mkdir -p /root/.steam 2>/dev/null -chmod -R 777 /root/.steam 2>/dev/null +# SteamCMD Update echo " " echo "Updating V-Rising Dedicated Server files..." echo " " -/usr/bin/steamcmd +@sSteamCmdForcePlatformType windows +force_install_dir "$s" +login anonymous +app_update 1829350 $beta_arg validate +quit -printf "steam_appid: " -cat "$s/steam_appid.txt" + +# Phase 1: Update SteamCMD itself to avoid restart loops breaking arguments +echo "Update SteamCMD..." +steamcmd +login anonymous +quit + +# Phase 2: Install the game +echo "Installing/Updating V Rising..." +steamcmd +@sSteamCmdForcePlatformType windows +force_install_dir "$s" +login anonymous +app_info_update 1 +app_update 1829350 $beta_arg validate +quit + +if [ -f "$s/steam_appid.txt" ]; then + printf "steam_appid: " + cat "$s/steam_appid.txt" +fi echo " " if ! grep -q -o 'avx[^ ]*' /proc/cpuinfo; then @@ -92,12 +127,9 @@ update_json_settings() { for var in "${env_vars[@]}"; do local raw_value="${!var}" - # Remove the prefix and convert to lowercase for matching local stripped_name="${var#${prefix}}" - # Convert to lowercase and replace underscores with dots for nested paths local search_key=$(echo "$stripped_name" | tr '[:upper:]' '[:lower:]' | sed 's/__/./g') - # Find the key path with case-insensitive matching and get the original value type local key_info key_info=$(jq -r --arg key "$search_key" ' def find_path($obj; $key_parts; $current_path; $current_type): @@ -130,13 +162,11 @@ update_json_settings() { jq_set="$jq_path = \"${raw_value//\"/\\\"}\"" ;; "boolean") - # Convert to lowercase for case-insensitive comparison local lower_value=$(echo "$raw_value" | tr '[:upper:]' '[:lower:]') if [[ ! "$lower_value" =~ ^(true|false)$ ]]; then echo "Error: '$matched_path' must be a boolean (true/false), skipping..." continue fi - # Always use lowercase true/false in the output jq_set="$jq_path = $lower_value" ;; "number"|"integer") @@ -147,9 +177,7 @@ update_json_settings() { jq_set="$jq_path = $raw_value" ;; "array") - # Special handling for array types - try to parse as JSON array if [[ "$raw_value" =~ ^\[.*\]$ ]]; then - # If it looks like a JSON array, try to parse it if jq -e . <<< "$raw_value" >/dev/null 2>&1; then jq_set="$jq_path = $raw_value" else @@ -157,12 +185,10 @@ update_json_settings() { continue fi else - # If it's not a JSON array, treat as a single value array jq_set="$jq_path = [\"$raw_value\"]" fi ;; *) - # For unknown types, try to preserve the original type if [[ "$raw_value" =~ ^(true|false)$ ]]; then jq_set="$jq_path = $raw_value" elif [[ "$raw_value" =~ ^-?[0-9]+(\.[0-9]+)?$ ]]; then @@ -175,31 +201,6 @@ update_json_settings() { if jq -e "$jq_set" "$tmp_file" > "${tmp_file}.new" 2>/dev/null; then mv "${tmp_file}.new" "$tmp_file" - else - echo "Failed to update: $matched_path" - echo " jq command: jq '$jq_set' $tmp_file" - fi - else - # Try to find the key with exact case for better error message - local exact_key=$(echo "$stripped_name" | tr '_' '.') - local key_exists=false - - # Check if the key exists in the JSON (case insensitive) - if jq -e --arg key "$exact_key" ' - def key_exists($obj; $key_parts): - if ($key_parts | length) == 0 then - true - else - $obj | to_entries | any( - .key | ascii_downcase == $key_parts[0] - and key_exists(.value; $key_parts[1:]) - ) - end; - key_exists(.; $key | split(".")) - ' "$tmp_file" >/dev/null 2>&1; then - echo "Found key but couldn't update (possible type mismatch): $stripped_name" - else - echo "Ignoring non-existent setting: $stripped_name" fi fi done @@ -209,7 +210,7 @@ update_json_settings() { } echo " " -mkdir "$p/Settings" 2>/dev/null +mkdir -p "$p/Settings" 2>/dev/null if [ ! -f "$p/Settings/ServerGameSettings.json" ]; then echo "$p/Settings/ServerGameSettings.json not found. Copying default file." cp "$s/VRisingServer_Data/StreamingAssets/Settings/ServerGameSettings.json" "$p/Settings/" 2>&1 @@ -238,25 +239,25 @@ if ! [ -f "${p}/$logfile" ]; then touch "$p/$logfile" fi -cd "$s" || { - echo "Failed to cd to $s" - exit 1 -} +cd "$s" || exit 1 + echo "Starting V Rising Dedicated Server with name $SERVERNAME" -echo "Trying to remove /tmp/.X0-lock" -rm /tmp/.X0-lock 2>&1 echo " " echo "Starting Xvfb" Xvfb :0 -screen 0 1024x768x16 & + +echo "Waiting for Xvfb to be ready..." +sleep 2 + +echo "Initializing Wine prefix..." +WINEDLLOVERRIDES="mscoree,mshtml=" DISPLAY=:0.0 wineboot --init +sleep 2 + echo "Launching wine64 V Rising" echo " " -v() { - DISPLAY=:0.0 wine64 /mnt/vrising/server/VRisingServer.exe -persistentDataPath $p -serverName "$SERVERNAME" "$override_savename" -logFile "$p/$logfile" "$game_port" "$query_port" 2>&1 & -} -v -# Gets the PID of the last command + +DISPLAY=:0.0 wine64 /mnt/vrising/server/VRisingServer.exe -persistentDataPath "$p" -serverName "$SERVERNAME" "$override_savename" -logFile "$p/$logfile" "$game_port" "$query_port" 2>&1 & ServerPID=$! -# Tail log file and waits for Server PID to exit /usr/bin/tail -n 0 -f "$p/$logfile" & wait $ServerPID