├── .github ├── ISSUE_TEMPLATE │ ├── bug-report.yml │ ├── config.yml │ ├── feature-request.yml │ └── question.yml ├── dependabot.yml └── workflows │ ├── ci.yml │ ├── docker-scout-scan.yml │ ├── pr.yml │ └── release.yml ├── .gitignore ├── LICENSE ├── README.md ├── docker-compose-proton.yml ├── docker-compose.yml ├── dockerfiles ├── Dockerfile └── proton.Dockerfile ├── docs ├── SERVER_DIFFICULTY.md └── SERVER_ROLES.md ├── scripts ├── default │ ├── bootstrap │ ├── common │ ├── defaults │ ├── enshrouded-backup │ ├── enshrouded-bootstrap-shared │ ├── enshrouded-force-update │ ├── enshrouded-reset-roles │ └── enshrouded-updater-shared ├── proton │ ├── enshrouded-bootstrap │ ├── enshrouded-server │ └── enshrouded-updater └── wine │ ├── enshrouded-bootstrap │ ├── enshrouded-server │ └── enshrouded-updater └── supervisord.conf /.github/ISSUE_TEMPLATE/bug-report.yml: -------------------------------------------------------------------------------- 1 | name: 🐛 Bug report 2 | description: Report a bug in enshrouded-server to help us fix it 3 | labels: [ "bug 🐞" ] 4 | body: 5 | - type: checkboxes 6 | attributes: 7 | label: Is there an existing issue for this? 8 | description: Please search existing issues to avoid creating duplicates. 9 | options: 10 | - label: I have searched the existing issues 11 | required: true 12 | 13 | - type: input 14 | attributes: 15 | label: Used image version 16 | description: What version of the image, are you currently using? If you use latest tag, pls provide also the sha256 hash. 17 | validations: 18 | required: true 19 | 20 | - type: textarea 21 | attributes: 22 | label: Used docker compose file or docker command 23 | description: | 24 | Pls remove any sensitive information from the file or command. 25 | validations: 26 | required: false 27 | 28 | - type: textarea 29 | attributes: 30 | label: What you expected to see, versus what you actually saw 31 | description: A clear and concise description of what you expected to happen. 32 | validations: 33 | required: true 34 | 35 | - type: textarea 36 | attributes: 37 | label: Logs from the container 38 | description: If possible, include logs from the container. You can get these with `docker compose logs` or `docker logs`. 39 | validations: 40 | required: false 41 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.yml: -------------------------------------------------------------------------------- 1 | name: 🚀 Feature request 2 | description: Suggest an idea for enshrouded-server 3 | labels: [ "feature-request 🚀" ] 4 | body: 5 | - type: checkboxes 6 | attributes: 7 | label: Is there an existing issue for this? 8 | description: Please search existing issues to avoid creating duplicates. 9 | options: 10 | - label: I have searched the existing issues 11 | required: true 12 | 13 | - type: textarea 14 | attributes: 15 | label: Feature description 16 | description: Describe the feature you'd like. 17 | validations: 18 | required: true 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.yml: -------------------------------------------------------------------------------- 1 | name: ❓ Questions 2 | description: Ask a question about the project 3 | labels: [ "question❓" ] 4 | body: 5 | - type: checkboxes 6 | attributes: 7 | label: Is there an existing issue for this? 8 | description: Please search existing issues to avoid creating duplicates. 9 | options: 10 | - label: I have searched the existing issues 11 | required: true 12 | 13 | - type: textarea 14 | attributes: 15 | label: Question 16 | description: Describe your question in detail. 17 | validations: 18 | required: true 19 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Please see the documentation for all configuration options: 2 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 3 | 4 | version: 2 5 | updates: 6 | # Keep Docker dependencies up to date 7 | - package-ecosystem: "docker" 8 | directory: "/dockerfiles" 9 | schedule: 10 | interval: "weekly" 11 | day: friday 12 | 13 | # Keep Github Actions up to date 14 | - package-ecosystem: "github-actions" 15 | directory: "/" 16 | schedule: 17 | interval: "weekly" 18 | day: friday 19 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths-ignore: 8 | - .github/** 9 | - README.md 10 | - LICENSE 11 | pull_request: 12 | branches: 13 | - main 14 | workflow_dispatch: 15 | 16 | concurrency: CI-${{ github.ref }} 17 | 18 | jobs: 19 | build-proton: 20 | uses: mornedhels/workflow-center-public/.github/workflows/docker-build.yml@main 21 | with: 22 | image-name: enshrouded-server 23 | image-tag: dev-proton 24 | dockerfile: dockerfiles/proton.Dockerfile 25 | scan-category: proton 26 | secrets: 27 | CONTAINER_REGISTRY_PASSWORD: ${{ secrets.DOCKER_TOKEN }} 28 | DOCKERHUB_TOKEN: ${{ secrets.DOCKER_TOKEN }} 29 | build-wine-stable: 30 | uses: mornedhels/workflow-center-public/.github/workflows/docker-build.yml@main 31 | with: 32 | image-name: enshrouded-server 33 | image-tag: dev-wine 34 | dockerfile: dockerfiles/Dockerfile 35 | scan-category: wine-stable 36 | secrets: 37 | CONTAINER_REGISTRY_PASSWORD: ${{ secrets.DOCKER_TOKEN }} 38 | DOCKERHUB_TOKEN: ${{ secrets.DOCKER_TOKEN }} 39 | build-wine-staging: 40 | uses: mornedhels/workflow-center-public/.github/workflows/docker-build.yml@main 41 | with: 42 | image-name: enshrouded-server 43 | image-tag: dev-wine-staging 44 | dockerfile: dockerfiles/Dockerfile 45 | scan-category: wine-staging 46 | build-args: | 47 | WINE_BRANCH=staging 48 | secrets: 49 | CONTAINER_REGISTRY_PASSWORD: ${{ secrets.DOCKER_TOKEN }} 50 | DOCKERHUB_TOKEN: ${{ secrets.DOCKER_TOKEN }} 51 | update-readme: 52 | if: github.event_name != 'pull_request' 53 | runs-on: ubuntu-latest 54 | needs: 55 | - build-proton 56 | - build-wine-stable 57 | - build-wine-staging 58 | steps: 59 | - uses: actions/checkout@v4 60 | - name: Update Docker Hub Description 61 | uses: peter-evans/dockerhub-description@v4 62 | with: 63 | username: ${{ vars.DOCKER_USER }} 64 | password: ${{ secrets.DOCKER_TOKEN }} 65 | repository: ${{ vars.DOCKER_USER }}/enshrouded-server 66 | -------------------------------------------------------------------------------- /.github/workflows/docker-scout-scan.yml: -------------------------------------------------------------------------------- 1 | name: Docker Scout Scan 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * 5' 6 | workflow_dispatch: 7 | 8 | jobs: 9 | docker-scout-scan-latest: 10 | uses: mornedhels/workflow-center-public/.github/workflows/docker-scout.yml@main 11 | with: 12 | image-name: enshrouded-server 13 | scan-category: proton-latest 14 | secrets: 15 | DOCKERHUB_TOKEN: ${{ secrets.DOCKER_TOKEN }} 16 | docker-scout-scan-dev: 17 | uses: mornedhels/workflow-center-public/.github/workflows/docker-scout.yml@main 18 | with: 19 | image-name: enshrouded-server 20 | image-tag: dev-proton 21 | scan-category: proton-dev 22 | secrets: 23 | DOCKERHUB_TOKEN: ${{ secrets.DOCKER_TOKEN }} 24 | -------------------------------------------------------------------------------- /.github/workflows/pr.yml: -------------------------------------------------------------------------------- 1 | name: PR-Automation 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | dependabot: 10 | runs-on: ubuntu-latest 11 | if: github.event_name == 'pull_request' && github.actor == 'dependabot[bot]' 12 | permissions: 13 | contents: write 14 | steps: 15 | - name: generate token for automerge 16 | id: automerge-app-token 17 | uses: getsentry/action-github-app-token@v3 18 | with: 19 | app_id: ${{ secrets.AUTOMERGE_APP_ID }} 20 | private_key: ${{ secrets.AUTOMERGE_APP_PRIVATE_KEY }} 21 | - name: Enable auto-merge for Dependabot PRs 22 | run: gh pr merge ${{github.event.pull_request.html_url}} --auto --rebase 23 | env: 24 | GITHUB_TOKEN: ${{ steps.automerge-app-token.outputs.token }} 25 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | release: 5 | types: [released] 6 | 7 | concurrency: Release-${{ github.ref }} 8 | 9 | jobs: 10 | docker-build-proton: 11 | uses: mornedhels/workflow-center-public/.github/workflows/docker-build.yml@main 12 | with: 13 | image-name: enshrouded-server 14 | dockerfile: dockerfiles/proton.Dockerfile 15 | scan-category: proton-latest 16 | image-tag: | 17 | latest 18 | stable-proton 19 | ${{ github.event.release.tag_name }} 20 | ${{ github.event.release.tag_name }}-proton 21 | secrets: 22 | CONTAINER_REGISTRY_PASSWORD: ${{ secrets.DOCKER_TOKEN }} 23 | DOCKERHUB_TOKEN: ${{ secrets.DOCKER_TOKEN }} 24 | docker-build-wine: 25 | uses: mornedhels/workflow-center-public/.github/workflows/docker-build.yml@main 26 | with: 27 | image-name: enshrouded-server 28 | dockerfile: dockerfiles/Dockerfile 29 | scan-category: wine-stable-latest 30 | image-tag: | 31 | stable-wine 32 | ${{ github.event.release.tag_name }}-wine 33 | secrets: 34 | CONTAINER_REGISTRY_PASSWORD: ${{ secrets.DOCKER_TOKEN }} 35 | DOCKERHUB_TOKEN: ${{ secrets.DOCKER_TOKEN }} 36 | update-readme: 37 | runs-on: ubuntu-latest 38 | needs: [docker-build-proton,docker-build-wine] 39 | steps: 40 | - uses: actions/checkout@v4 41 | - name: Update Docker Hub Description 42 | uses: peter-evans/dockerhub-description@v4 43 | with: 44 | username: ${{ vars.DOCKER_USER }} 45 | password: ${{ secrets.DOCKER_TOKEN }} 46 | repository: ${{ vars.DOCKER_USER }}/enshrouded-server 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /.vs/* 3 | /game 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 mornedhels 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Enshrouded-Dedicated-Server 2 | 3 | [![Docker Pulls](https://img.shields.io/docker/pulls/mornedhels/enshrouded-server.svg)](https://hub.docker.com/r/mornedhels/enshrouded-server) 4 | [![Docker Stars](https://img.shields.io/docker/stars/mornedhels/enshrouded-server.svg)](https://hub.docker.com/r/mornedhels/enshrouded-server) 5 | [![Docker Image Size (tag)](https://img.shields.io/docker/image-size/mornedhels/enshrouded-server/latest)](https://hub.docker.com/r/mornedhels/enshrouded-server) 6 | [![GitHub](https://img.shields.io/github/license/mornedhels/enshrouded-server)](https://github.com/mornedhels/enshrouded-server/blob/main/LICENSE) 7 | 8 | [![GitHub](https://img.shields.io/badge/Repository-mornedhels/enshrouded--server-blue?logo=github)](https://github.com/mornedhels/enshrouded-server) 9 | 10 | Docker image for the game Enshrouded. The image is based on 11 | the [steamcmd](https://hub.docker.com/r/cm2network/steamcmd/) image and uses supervisor to handle startup, automatic 12 | updates and cleanup. 13 | 14 | ## Environment Variables 15 | 16 | | Variable | Required | Default | Contraints | Description | WIP | 17 | |--------------------------------------------------------------------------------------------------------------|:--------:|---------------------|-----------------------|--------------------------------------------------------------------------------------------------------------------|:---:| 18 | | `SERVER_NAME` | | `Enshrouded Server` | string | The name of the server | ️ | 19 | | `SERVER_SLOT_COUNT` | | `16` | integer (1-16) | Max allowed concurrent players | | 20 | | `SERVER_QUERYPORT` | | `15637` | integer | The steam query port for the server | | 21 | | `SERVER_IP` | | `0.0.0.0` | string (ipv4) | Server IP for internal network configuration | | 22 | | `SERVER_SAVE_DIR` | | `./savegame` | string | Folder for savegames (relative and absolute paths are supported) | | 23 | | `SERVER_LOG_DIR` | | `./logs` | string | Folder for logs (relative and absolute paths are supported) | | 24 | | `SERVER_VOICE_CHAT_MODE` | | `Proximity` | Proximity \| Global | This setting allows switching between the proximity voice chat and the global, server-wide voice chat | | 25 | | `SERVER_ENABLE_VOICE_CHAT` | | `false` | boolean (true, false) | This setting allows switching voice chat completely off or enabling it. | | 26 | | `SERVER_ENABLE_TEXT_CHAT` | | `false` | boolean (true, false) | This setting allows switching text chat completely off or enabling it. | | 27 | | `PUID` | | `4711` | integer | The UID to run server as (file permission) | | 28 | | `PGID` | | `4711` | integer | The GID to run server as (file permission) | | 29 | | `UPDATE_CRON` | | | string (cron format) | Update game server files cron (eg. `*/30 * * * *` check for updates every 30 minutes) | | 30 | | `UPDATE_CHECK_PLAYERS` | | `false` | boolean (true, false) | Should the update check if someone is connected | | 31 | | `BACKUP_CRON` | | | string (cron format) | Backup game server files cron (eg. `*/15 * * * *` backup saves every 15 minutes) - don't set cron under 10 minutes | | 32 | | `BACKUP_DIR` | | `./backup` | string | Folder for backups (relative and absolute paths are supported) | | 33 | | `BACKUP_MAX_COUNT` | | `0` | integer | Number of backups to keep (0 means infinite) | | 34 | | `GAME_BRANCH` | | `public` | string | Steam branch (eg. testing) of the Enshrouded server | | 35 | | `STEAMCMD_ARGS` | | `validate` | string | Additional steamcmd args for the updater | | 36 | | `SERVER_PASSWORD` ⚠️DEPRECATED | | | string | ⚠️ DEPRECATED: The password for the server (Enshrouded ignores this value - use Server Roles instead) | | 37 | | **[Server Roles](https://github.com/mornedhels/enshrouded-server/blob/main/docs/SERVER_ROLES.md)** | | | | further informations can be found following the link | | 38 | | **[Server Difficulty](https://github.com/mornedhels/enshrouded-server/blob/main/docs/SERVER_DIFFICULTY.md)** | | | | further informations can be found following the link | ⚠️ | 39 | 40 | All environment Variables prefixed with SERVER, are the available enshrouded_server.json options 41 | (see [Enshrouded Docs](https://enshrouded.zendesk.com/hc/en-us/articles/16055441447709-Dedicated-Server-Configuration)) 42 | 43 | ⚠️: Work in Progress 44 | 45 | ### Additional Information 46 | 47 | * During the update process, the container temporarily requires more disk space (up to 2x the game size). 48 | * Server role configuration can be done via the `enshrouded_server.json` file directly or the `SERVER_ROLE__XYZ` 49 | environment vars. The file is located in the `game/server` folder. More information can be found in 50 | the [official documentation](https://enshrouded.zendesk.com/hc/en-us/articles/19191581489309-Server-Roles-Configuration). 51 | 52 | ### Hooks 53 | 54 | | Variable | Description | WIP | 55 | |--------------------|----------------------------------------|:---:| 56 | | `BOOTSTRAP_HOOK` | Command to run after general bootstrap | | 57 | | `UPDATE_PRE_HOOK` | Command to run before update | | 58 | | `UPDATE_POST_HOOK` | Command to run after update | | 59 | | `BACKUP_PRE_HOOK` | Command to run before backup & cleanup | | 60 | | `BACKUP_POST_HOOK` | Command to run after backup & cleanup | | 61 | 62 | The scripts will wait for the hook to resolve/return before continuing. 63 | 64 | ⚠️: Work in Progress 65 | 66 | ## Image Tags 67 | 68 | | Tag | Virtualization | Description | 69 | |--------------------|----------------|------------------------------------------| 70 | | `latest` | proton | Latest image based on proton | 71 | | `` | proton | Pinned image based on proton (>= 1.x.x) | 72 | | `stable-proton` | proton | Same as latest image | 73 | | `-proton` | proton | Pinned image based on proton | 74 | | `stable-wine` | wine | Latest image based on wine | 75 | | `-wine` | wine | Pinned image based on wine | 76 | | `dev-proton` | proton | Dev build based on proton | 77 | | `dev-wine` | wine | Dev build based on wine | 78 | | `dev-wine-staging` | wine | Dev build based on wine (staging branch) | 79 | 80 | ## Ports (default) 81 | 82 | | Port | Description | 83 | |-----------|------------------| 84 | | 15637/udp | Steam query port | 85 | 86 | ## Volumes 87 | 88 | | Volume | Description | 89 | |-----------------|----------------------------------| 90 | | /opt/enshrouded | Game files (steam download path) | 91 | 92 | **Note:** By default the volumes are created with the UID and GID 4711 (that user should not exist). To change this, set 93 | the environment variables `PUID` and `PGID`. 94 | 95 | ## Recommended System Requirements 96 | 97 | * CPU: >= 6 cores 98 | * RAM: >= 16 GB 99 | * Disk: >= 30 GB (preferably SSD) 100 | 101 | **[Official Docs](https://enshrouded.zendesk.com/hc/en-us/articles/16055628734109-Recommended-Server-Specifications)** 102 | 103 | ## Usage 104 | 105 | ### Docker 106 | 107 | ```bash 108 | docker run -d --name enshrouded \ 109 | --hostname enshrouded \ 110 | --restart=unless-stopped \ 111 | -p 15637:15637/udp \ 112 | -v ./game:/opt/enshrouded \ 113 | -e SERVER_NAME="Enshrouded Server" \ 114 | -e SERVER_PASSWORD="secret" \ 115 | -e UPDATE_CRON="*/30 * * * *" \ 116 | -e PUID=4711 \ 117 | -e PGID=4711 \ 118 | mornedhels/enshrouded-server:latest 119 | ``` 120 | 121 | ### Docker Compose 122 | 123 | ```yaml 124 | services: 125 | enshrouded: 126 | image: mornedhels/enshrouded-server:latest 127 | container_name: enshrouded 128 | hostname: enshrouded 129 | restart: unless-stopped 130 | stop_grace_period: 90s 131 | ports: 132 | - "15637:15637/udp" 133 | volumes: 134 | - ./game:/opt/enshrouded 135 | environment: 136 | - SERVER_NAME=Enshrouded Server 137 | - SERVER_PASSWORD=secret 138 | - UPDATE_CRON=*/30 * * * * 139 | - PUID=4711 140 | - PGID=4711 141 | ``` 142 | 143 | **Note:** The volumes are created next to the docker-compose.yml file. If you want to create the volumes, in the default 144 | location (eg. /var/lib/docker) you can use the following compose file: 145 | 146 | ```yaml 147 | services: 148 | enshrouded: 149 | image: mornedhels/enshrouded-server:latest 150 | container_name: enshrouded 151 | hostname: enshrouded 152 | restart: unless-stopped 153 | stop_grace_period: 90s 154 | ports: 155 | - "15637:15637/udp" 156 | volumes: 157 | - game:/opt/enshrouded 158 | environment: 159 | - SERVER_NAME=Enshrouded Server 160 | - SERVER_PASSWORD=secret 161 | - UPDATE_CRON=*/30 * * * * 162 | - PUID=4711 163 | - PGID=4711 164 | 165 | volumes: 166 | game: 167 | ``` 168 | 169 | ## Backup 170 | 171 | The image includes a backup script that creates a zip file of the last saved game state. To enable backups, set 172 | the `BACKUP_CRON` environment variable. To limit the number of backups, set the `BACKUP_MAX_COUNT` environment variable. 173 | 174 | To restore a backup, stop the server and simply extract the zip file to the savegame folder and start the server up 175 | again. If you want to keep the current savegame, make sure to make a backup before deleting or overwriting the files. 176 | 177 | > [!WARNING] 178 | > Verify the permissions of the extracted files. The files should be owned by the user with the UID and GID set in the 179 | > environment variables. If the image is running in privileged mode, the files will be automatically chowned to the 180 | > given `UID` and `GID`. 181 | 182 | ## Commands 183 | 184 | * **Force Update:** 185 | ```bash 186 | docker compose exec enshrouded supervisorctl start enshrouded-force-update 187 | ``` 188 | * **Reset Server Roles:** (Restarts the whole docker container) ⚠️ 189 | ```bash 190 | docker compose exec enshrouded supervisorctl start enshrouded-reset-roles 191 | ``` 192 | * **Restart Enshrouded Server:** (can be used for periodic restarts) 193 | ```bash 194 | docker compose exec enshrouded supervisorctl restart enshrouded-server 195 | ``` 196 | 197 | ## Known Issues 198 | 199 | * The server doesn't start (not logging `'HostOnline' (up)!`) or the update fails with following error: 200 | ``` 201 | Error! App '2278520' state is 0x202 after update job. 202 | ``` 203 | This means there is probably something wrong with your file permissions, or you don't have enough disk space left. 204 | Make sure the UID and GID are correct and the files are owned by the correct user. 205 | * The (auto-)update fails with the following error: 206 | ``` 207 | Error! App '2278520' state is 0x6 after update job. 208 | ``` 209 | Officially this means the updater has no connection to the content servers. 210 |
But there could also be something wrong with the steam 211 | appmanifest ([#119](https://github.com/mornedhels/enshrouded-server/issues/119)). To fix this, you can use the **force 212 | update** command. 213 | -------------------------------------------------------------------------------- /docker-compose-proton.yml: -------------------------------------------------------------------------------- 1 | services: 2 | enshrouded: 3 | build: 4 | context: . 5 | dockerfile: dockerfiles/proton.Dockerfile 6 | image: mornedhels/enshrouded-server:dev-proton 7 | container_name: enshrouded 8 | hostname: enshrouded 9 | restart: unless-stopped 10 | stop_grace_period: 90s 11 | ports: 12 | - "15637:15637/udp" 13 | volumes: 14 | - ./game:/opt/enshrouded 15 | environment: 16 | - SERVER_NAME=MornedhelsTest 17 | - PUID=4711 18 | - PGID=4711 19 | - UPDATE_CRON=*/30 * * * * 20 | - log_level=50 21 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | enshrouded: 3 | build: 4 | context: . 5 | dockerfile: dockerfiles/Dockerfile 6 | args: 7 | WINE_BRANCH: stable 8 | image: mornedhels/enshrouded-server:dev 9 | container_name: enshrouded 10 | hostname: enshrouded 11 | restart: unless-stopped 12 | stop_grace_period: 90s 13 | ports: 14 | - "15637:15637/udp" 15 | volumes: 16 | - ./game:/opt/enshrouded 17 | environment: 18 | - SERVER_NAME=MornedhelsTest 19 | - PUID=4711 20 | - PGID=4711 21 | - UPDATE_CRON=*/30 * * * * 22 | - log_level=50 23 | -------------------------------------------------------------------------------- /dockerfiles/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM steamcmd/steamcmd:ubuntu-24@sha256:cd199e57fa1474a896666c36dd623db9b24d4a2284246242df603d0dfb70bd80 2 | LABEL maintainer="docker@mornedhels.de" 3 | 4 | # Install prerequisites 5 | RUN apt-get update \ 6 | && DEBIAN_FRONTEND="noninteractive" apt-get install -y --no-install-recommends \ 7 | curl \ 8 | supervisor \ 9 | cron \ 10 | rsyslog \ 11 | jq \ 12 | zip \ 13 | python3 \ 14 | python3-pip \ 15 | && apt autoremove --purge && apt clean \ 16 | && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 17 | 18 | # Install wine 19 | ARG WINE_BRANCH=stable 20 | RUN dpkg --add-architecture i386 \ 21 | && mkdir -pm755 /etc/apt/keyrings \ 22 | && curl -o /etc/apt/keyrings/winehq-archive.key https://dl.winehq.org/wine-builds/winehq.key \ 23 | && curl -O --output-dir /etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/ubuntu/dists/$(grep VERSION_CODENAME= /etc/os-release | cut -d= -f2)/winehq-$(grep VERSION_CODENAME= /etc/os-release | cut -d= -f2).sources \ 24 | && apt update && DEBIAN_FRONTEND="noninteractive" apt -y --install-recommends install wine-${WINE_BRANCH} \ 25 | && ln -s /opt/wine-$WINE_BRANCH/bin/* /usr/local/bin/ \ 26 | && apt autoremove --purge && apt clean \ 27 | && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 28 | 29 | # Install winetricks (unused) 30 | RUN curl -o /tmp/winetricks https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks \ 31 | && chmod +x /tmp/winetricks && install -m 755 /tmp/winetricks /usr/local/bin/winetricks \ 32 | && rm -rf /tmp/* 33 | 34 | # MISC 35 | RUN mkdir -p /usr/local/etc /var/log/supervisor /var/run/enshrouded /usr/local/etc/supervisor/conf.d/ /opt/enshrouded /home/enshrouded/.steam \ 36 | && groupadd -g "${PGID:-4711}" -o enshrouded \ 37 | && useradd -g "${PGID:-4711}" -u "${PUID:-4711}" -o --create-home enshrouded \ 38 | && sed -i '/imklog/s/^/#/' /etc/rsyslog.conf \ 39 | && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 40 | 41 | COPY ../supervisord.conf /etc/supervisor/supervisord.conf 42 | COPY --chmod=755 ../scripts/default/* ../scripts/wine/* /usr/local/etc/enshrouded/ 43 | 44 | WORKDIR /usr/local/etc/enshrouded 45 | CMD ["/usr/local/etc/enshrouded/bootstrap"] 46 | ENTRYPOINT [] 47 | -------------------------------------------------------------------------------- /dockerfiles/proton.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM steamcmd/steamcmd:ubuntu-24@sha256:cd199e57fa1474a896666c36dd623db9b24d4a2284246242df603d0dfb70bd80 AS builder 2 | 3 | ARG GE_PROTON_VERSION="10-3" 4 | 5 | # Install prerequisites 6 | RUN dpkg --add-architecture i386 \ 7 | && apt-get update \ 8 | && DEBIAN_FRONTEND="noninteractive" apt-get install -y --no-install-recommends \ 9 | curl \ 10 | tar \ 11 | dbus \ 12 | && apt autoremove --purge && apt clean \ 13 | && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 14 | 15 | # install proton 16 | RUN curl -sLOJ "https://github.com/GloriousEggroll/proton-ge-custom/releases/download/GE-Proton${GE_PROTON_VERSION}/GE-Proton${GE_PROTON_VERSION}.tar.gz" \ 17 | && mkdir -p /tmp/proton \ 18 | && tar -xzf GE-Proton*.tar.gz -C /tmp/proton --strip-components=1 \ 19 | && rm GE-Proton*.* \ 20 | && rm -f /etc/machine-id \ 21 | && dbus-uuidgen --ensure=/etc/machine-id 22 | 23 | 24 | FROM steamcmd/steamcmd:ubuntu-24@sha256:cd199e57fa1474a896666c36dd623db9b24d4a2284246242df603d0dfb70bd80 25 | LABEL maintainer="docker@mornedhels.de" 26 | 27 | # Install dependencies 28 | RUN dpkg --add-architecture i386 \ 29 | && apt-get update \ 30 | && DEBIAN_FRONTEND="noninteractive" apt-get install -y --no-install-recommends \ 31 | curl \ 32 | supervisor \ 33 | cron \ 34 | rsyslog \ 35 | jq \ 36 | zip \ 37 | python3 \ 38 | python3-pip \ 39 | libfreetype6 \ 40 | libfreetype6:i386 \ 41 | && apt autoremove --purge && apt clean \ 42 | && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 43 | 44 | # Install winetricks (unused) 45 | RUN curl -o /tmp/winetricks https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks \ 46 | && chmod +x /tmp/winetricks && install -m 755 /tmp/winetricks /usr/local/bin/winetricks \ 47 | && rm -rf /tmp/* 48 | 49 | # MISC 50 | RUN mkdir -p /usr/local/etc /var/log/supervisor /var/run/enshrouded /usr/local/etc/supervisor/conf.d/ /opt/enshrouded /home/enshrouded/.steam/sdk32 /home/enshrouded/.steam/sdk64 \ 51 | && groupadd -g "${PGID:-4711}" -o enshrouded \ 52 | && useradd -g "${PGID:-4711}" -u "${PUID:-4711}" -o --create-home enshrouded \ 53 | && ln -f /root/.steam/sdk32/steamclient.so /home/enshrouded/.steam/sdk32/steamclient.so \ 54 | && ln -f /root/.steam/sdk64/steamclient.so /home/enshrouded/.steam/sdk64/steamclient.so \ 55 | && sed -i '/imklog/s/^/#/' /etc/rsyslog.conf \ 56 | && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 57 | 58 | COPY --from=builder /tmp/proton /usr/local/bin 59 | COPY --from=builder /etc/machine-id /etc/machine-id 60 | 61 | COPY ../supervisord.conf /etc/supervisor/supervisord.conf 62 | COPY --chmod=755 ../scripts/default/* ../scripts/proton/* /usr/local/etc/enshrouded/ 63 | 64 | WORKDIR /usr/local/etc/enshrouded 65 | CMD ["/usr/local/etc/enshrouded/bootstrap"] 66 | ENTRYPOINT [] 67 | -------------------------------------------------------------------------------- /docs/SERVER_DIFFICULTY.md: -------------------------------------------------------------------------------- 1 | # [Server Difficulty](https://enshrouded.zendesk.com/hc/en-us/articles/20453241249821-Server-Difficulty-Settings) 2 | 3 | ## Environment Variables 4 | 5 | | Variable | Default | Contraints | Description | WIP | 6 | |------------------------------------------|------------------------|-----------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---:| 7 | | **Server Difficulty** | | | prefix with `SERVER_GS_` e.g. `SERVER_GS_PRESET` (alias gamesettings) | ⚠️ | 8 | |   `PRESET` | `Default` | Default \| Relaxed \| Hard \| Survival \| Custom | The difficulty preset for the server. Other settings only work with preset `Custom` | ⚠️ | 9 | |   `PLAYER_HEALTH_FACTOR` | `1` | 0.25 - 4 | Scales the max health for players by a factor. Ingame, the factor is represented by a percentage | ⚠️ | 10 | |   `PLAYER_MANA_FACTOR` | `1` | 0.25 - 4 | Scales the max mana for players by a factor. Ingame, the factor is represented by a percentage | ⚠️ | 11 | |   `PLAYER_STAMINA_FACTOR` | `1` | 0.25 - 4 | Scales the max stamina for players by a factor. Ingame, the factor is represented by a percentage | ⚠️ | 12 | |   `PLAYER_BODY_HEAT_FACTOR` | `1` | low: 0.5 \| default: 1 \| high: 1.5 \| max: 2 | Scales the max amount of available body heat in the player. The higher the factor the longer the player can stay in very cold areas before hypothermia sets in. | ⚠️ | 13 | |   `ENABLE_DURABILITY` | `true` | boolean (true, false) | Whether weapon durability is enabled | ⚠️ | 14 | |   `ENABLE_STARVING_DEBUFF` | `false` | boolean (true, false) | Enables hunger and starvation. During starvation, the player loses health periodically until death if no food or drink is consumed | ⚠️ | 15 | |   `FOOD_BUFF_DURATION_FACTOR` | `1` | 0.5 - 2 | Scales food buff durations. Ingame, the factor is represented by a percentage | ⚠️ | 16 | |   `FROM_HUNGER_TO_STARVING` | `600000000000` | 300000000000 - 1200000000000 | This setting controls the length of the hungry state before the starving sets in. The unit in this setting is nanoseconds. Ingame the time is displayed in minutes | ⚠️ | 17 | |   `SHROUD_TIME_FACTOR` | `1` | 0.5 - 2 | Scales how long player characters can remain within the Shroud. Ingame, the factor is represented by a percentage | ⚠️ | 18 | |   `ENABLE_GLIDER_TURBULENCES` | `true` | boolean (true, false) | If turned off, the glider will not be affected by air turbulences, just as in previous versions of the game. | ⚠️ | 19 | |   `WEATHER_FREQUENCY` | `Normal` | Disabled \| Rare \| Normal \| Often | This setting allows defining how often new weather phenomena appear in the game world. | ⚠️ | 20 | |   `RANDOM_SPAWNER_AMOUNT` | `Normal` | Few \| Normal \| Many \| Extreme | This setting controls the amount of enemies in the world | ⚠️ | 21 | |   `MINING_DAMAGE_FACTOR` | `1` | 0.5 - 2 | This scales the mining damage. A higher mining damage leads to increased terraforming and more yield of resources per hit. Ingame, the factor is represented by a percentage | ⚠️ | 22 | |   `PLANT_GROWTH_SPEED_FACTOR` | `1` | 0.25 - 2 | Scales the value of the plant growth speed. Ingame, the factor is represented by a percentage | ⚠️ | 23 | |   `RESOURCE_DROP_STACK_AMOUNT_FACTOR` | `1` | 0.25 - 2 | Scales the amount of materials per loot stack in chests, defeated enemies etc. Ingame, the factor is represented by a percentage | ⚠️ | 24 | |   `FACTORY_PRODUCTION_SPEED_FACTOR` | `1` | 0.25 - 2 | Scales the length of production times for workshop items. Ingame, the factor is represented by a percentage | ⚠️ | 25 | |   `PERK_UPGRADE_RECYCLING_FACTOR` | `0.100000` | 0 - 1 | Scales the amount of Runes that are returned to you when salvaging upgraded weapons. Ingame, the factor is represented by a percentage | ⚠️ | 26 | |   `PERK_COST_FACTOR` | `1` | 0.25 - 2 | Scales the amount of Runes required for upgrading weapons. Ingame, the factor is represented by a percentage | ⚠️ | 27 | |   `EXPERIENCE_COMBAT_FACTOR` | `1` | 0.25 - 2 | Scales the amount of XP received through combat. Ingame, the factor is represented by a percentage | ⚠️ | 28 | |   `EXPERIENCE_MINING_FACTOR` | `1` | 0`?` - 2 | Scales the amount of XP received by mining resources. Ingame, the factor is represented by a percentage | ⚠️ | 29 | |   `EXPERIENCE_EXPLORATION_QUESTS_FACTOR` | `1` | 0.25 - 2 | Scales the amount of XP received by exploring and completing quests. Ingame, the factor is represented by a percentage | ⚠️ | 30 | |   `AGGRO_POOL_AMOUNT` | `Normal` | Few \| Normal \| Many \| Extreme | This setting controls how many enemies are allowed to attack at the same time. Ingame, the factor is represented by a percentage | ⚠️ | 31 | |   `ENEMY_DAMAGE_FACTOR` | `1` | 0.25 - 5 | Scales all enemy damage by this value - except for bosses. Ingame, the factor is represented by a percentage | ⚠️ | 32 | |   `ENEMY_HEALTH_FACTOR` | `1` | 0.25 - 4 | Scales all enemy health by this value - except for bosses. Ingame, the factor is represented by a percentage | ⚠️ | 33 | |   `ENEMY_STAMINA_FACTOR` | `1` | 0.5 - 2 | Scales all enemy stamina by this value. It will take longer to stun enemies with a higher enemy stamina. This excludes bosses. Ingame, the factor is represented by a percentage | ⚠️ | 34 | |   `ENEMY_PERCEPTION_RANGE_FACTOR` | `1` | 0.5 - 2 | Scales how far enemies can see and hear the player. This excludes bosses. Ingame, the factor is represented by a percentage | ⚠️ | 35 | |   `BOSS_DAMAGE_FACTOR` | `1` | 0.2 - 5 | This setting scales the damage of boss attacks. Ingame, the factor is represented by a percentage | ⚠️ | 36 | |   `BOSS_HEALTH_FACTOR` | `1` | 0.2 - 5 | Scales all health of bosses by this value. Ingame, the factor is represented by a percentage | ⚠️ | 37 | |   `THREAT_BONUS` | `1` | 0.25 - 4 | Scales the frequency of enemy attacks. This excludes bosses. Ingame, the factor is represented by a percentage | ⚠️ | 38 | |   `PACIFY_ALL_ENEMIES` | `false` | boolean (true, false) | If turned on, enemies won't attack the players until they are attacked. This excludes bosses | ⚠️ | 39 | |   `TAMING_STARTLE_REPERCUSSION` | `LoseSomeProgress` | KeepProgress \| LoseSomeProgress \| LoseAllProgress | This setting allows defining how the game reacts when the player startles the wildlife during taming. Progress is visualized by hearts in the game. | ⚠️ | 40 | |   `DAY_TIME_DURATION` | `1800000000000` | 120000000000 - 3600000000000 | Scales the length of daytime. A smaller value equals shorter daytime. The unit is nanoseconds. Ingame, the time is displayed in minutes | ⚠️ | 41 | |   `NIGHT_TIME_DURATION` | `720000000000` | 120000000000 - 1800000000000 | Scales the length of nighttime. A smaller value equals shorter nighttime. The unit is nanoseconds. Ingame, the time is displayed in minutes | ⚠️ | 42 | |   `TOMBSTONE_MODE` | `AddBackpackMaterials` | AddBackpackMaterials \| Everything \| NoTombstone | The players can either keep or lose all items from their backpack when dying. In the default setting, they only lose materials. Lost items are stored in a tombstone and can be recovered there | ⚠️ | 43 | 44 | ⚠️: Work in Progress 45 | 46 | > [!TIP] 47 | > The gameSettings config will be generated automatically with default values when you start the server without 48 | > specifying any environment variables. 49 | > 50 | > You can also adjust the settings directly in the `enshrouded_server.json` file. 51 | 52 | ## Example Usage 53 | 54 |
Expand 55 | 56 | With environment variables: 57 | 58 | ```yaml 59 | services: 60 | enshrouded: 61 | image: mornedhels/enshrouded-server:latest 62 | container_name: enshrouded 63 | hostname: enshrouded 64 | restart: unless-stopped 65 | stop_grace_period: 90s 66 | ports: 67 | - "15637:15637/udp" 68 | volumes: 69 | - ./game:/opt/enshrouded 70 | environment: 71 | - SERVER_NAME=Enshrouded Server 72 | - SERVER_ROLE_0_NAME=Default 73 | - SERVER_ROLE_0_PASSWORD=secret123 74 | - SERVER_GS_PRESET=Custom 75 | - SERVER_GS_PLAYER_HEALTH_FACTOR=2 76 | - SERVER_GS_PLAYER_MANA_FACTOR=2 77 | - SERVER_GS_PLAYER_STAMINA_FACTOR=2 78 | - SERVER_GS_PLAYER_BODY_HEAT_FACTOR=2 79 | - SERVER_GS_ENABLE_DURABILITY=true 80 | - SERVER_GS_ENABLE_STARVING_DEBUFF=false 81 | - SERVER_GS_FOOD_BUFF_DURATION_FACTOR=1 82 | - SERVER_GS_FROM_HUNGER_TO_STARVING=600000000000 83 | - SERVER_GS_SHROUD_TIME_FACTOR=1 84 | - SERVER_GS_ENABLE_GLIDER_TURBULENCES=false 85 | - SERVER_GS_WEATHER_FREQUENCY=Often 86 | - SERVER_GS_RANDOM_SPAWNER_AMOUNT=Normal 87 | - SERVER_GS_MINING_DAMAGE_FACTOR=1 88 | - SERVER_GS_PLANT_GROWTH_SPEED_FACTOR=1 89 | - SERVER_GS_RESOURCE_DROP_STACK_AMOUNT_FACTOR=1 90 | - SERVER_GS_FACTORY_PRODUCTION_SPEED_FACTOR=1 91 | - SERVER_GS_PERK_UPGRADE_RECYCLING_FACTOR=0.5 92 | - SERVER_GS_PERK_COST_FACTOR=1 93 | - SERVER_GS_EXPERIENCE_COMBAT_FACTOR=1 94 | - SERVER_GS_EXPERIENCE_MINING_FACTOR=1 95 | - SERVER_GS_EXPERIENCE_EXPLORATION_QUESTS_FACTOR=1 96 | - SERVER_GS_AGGRO_POOL_AMOUNT=Normal 97 | - SERVER_GS_ENEMY_DAMAGE_FACTOR=1 98 | - SERVER_GS_ENEMY_HEALTH_FACTOR=1 99 | - SERVER_GS_ENEMY_STAMINA_FACTOR=1 100 | - SERVER_GS_ENEMY_PERCEPTION_RANGE_FACTOR=1 101 | - SERVER_GS_BOSS_DAMAGE_FACTOR=1 102 | - SERVER_GS_BOSS_HEALTH_FACTOR=1 103 | - SERVER_GS_THREAT_BONUS=1 104 | - SERVER_GS_PACIFY_ALL_ENEMIES=false 105 | - SERVER_GS_TAMING_STARTLE_REPERCUSSION=LoseAllProgress 106 | - SERVER_GS_DAY_TIME_DURATION=1800000000000 107 | - SERVER_GS_NIGHT_TIME_DURATION=720000000000 108 | - SERVER_GS_TOMBSTONE_MODE=AddBackpackMaterials 109 | ``` 110 | 111 | Creates the following `enshrouded_server.json` file: 112 | 113 | ```json 114 | { 115 | "name": "Enshrouded Server", 116 | "password": "", 117 | "saveDirectory": "./savegame", 118 | "logDirectory": "./logs", 119 | "ip": "0.0.0.0", 120 | "queryPort": 15637, 121 | "slotCount": 16, 122 | "userGroups": [ 123 | { 124 | "name": "Custom", 125 | "password": "secret123", 126 | "canKickBan": false, 127 | "canAccessInventories": false, 128 | "canEditBase": false, 129 | "canExtendBase": false, 130 | "reservedSlots": 0 131 | } 132 | ], 133 | "gameSettingsPreset": "Custom", 134 | "gameSettings": { 135 | "playerHealthFactor": 2, 136 | "playerManaFactor": 2, 137 | "playerStaminaFactor": 2, 138 | "playerBodyHeatFactor": 2, 139 | "enableDurability": true, 140 | "enableStarvingDebuff": false, 141 | "foodBuffDurationFactor": 1, 142 | "fromHungerToStarving": 600000000000, 143 | "shroudTimeFactor": 1, 144 | "enableGliderTurbulences": false, 145 | "weatherFrequency": "Often", 146 | "randomSpawnerAmount": "Normal", 147 | "miningDamageFactor": 1, 148 | "plantGrowthSpeedFactor": 1, 149 | "resourceDropStackAmountFactor": 1, 150 | "factoryProductionSpeedFactor": 1, 151 | "perkUpgradeRecyclingFactor": 0.5, 152 | "perkCostFactor": 1, 153 | "experienceCombatFactor": 1, 154 | "experienceMiningFactor": 1, 155 | "experienceExplorationQuestsFactor": 1, 156 | "aggroPoolAmount": "Normal", 157 | "enemyDamageFactor": 1, 158 | "enemyHealthFactor": 1, 159 | "enemyStaminaFactor": 1, 160 | "enemyPerceptionRangeFactor": 1, 161 | "bossDamageFactor": 1, 162 | "bossHealthFactor": 1, 163 | "threatBonus": 1, 164 | "pacifyAllEnemies": false, 165 | "tamingStartleRepercussion": "LoseAllProgress", 166 | "dayTimeDuration": 1800000000000, 167 | "nightTimeDuration": 720000000000, 168 | "tombstoneMode": "AddBackpackMaterials" 169 | } 170 | } 171 | ``` 172 | 173 |
174 | -------------------------------------------------------------------------------- /docs/SERVER_ROLES.md: -------------------------------------------------------------------------------- 1 | # [Server Roles](https://enshrouded.zendesk.com/hc/en-us/articles/19191581489309-Server-Roles-Configuration) 2 | 3 | To configure server roles, you can use the `SERVER_ROLE__` environment variables. The index starts at 0. It will 4 | find the corresponding role in the `enshrouded_server.json` file and update the values accordingly. 5 | You can also just edit the `enshrouded_server.json` file directly. 6 | 7 | ## Environment Variables 8 | 9 | | Variable | Default | Contraints | Description | WIP | 10 | |---------------------------------|-----------|-----------------------|---------------------------------------------------------------------------------|:---:| 11 | | **Server Roles** | | | prefix with `SERVER_ROLE__` e.g. `SERVER_ROLE_0_NAME` (alias usergroups) | | 12 | |   `NAME` | `Default` | string | The name of the server role on index (starting with 0) | | 13 | |   `PASSWORD` | `""` | string | The password for the server role | | 14 | |   `CAN_KICK_BAN` | `false` | boolean (true, false) | Permission to kick and ban players | | 15 | |   `CAN_ACCESS_INVENTORIES` | `false` | boolean (true, false) | Permission to access inventories | | 16 | |   `CAN_EDIT_BASE` | `false` | boolean (true, false) | Permission to edit the base | | 17 | |   `CAN_EXTEND_BASE` | `false` | boolean (true, false) | Permission to extend the base | | 18 | |   `RESERVED_SLOTS` | `0` | integer | Number of reserved slots for the server role | | 19 | 20 | ## Example Usage 21 | 22 |
Expand 23 | 24 | With environment variables: 25 | 26 | ```yaml 27 | services: 28 | enshrouded: 29 | image: mornedhels/enshrouded-server:latest 30 | container_name: enshrouded 31 | hostname: enshrouded 32 | restart: unless-stopped 33 | stop_grace_period: 90s 34 | ports: 35 | - "15637:15637/udp" 36 | volumes: 37 | - ./game:/opt/enshrouded 38 | environment: 39 | - SERVER_NAME=Enshrouded Server 40 | - SERVER_ROLE_0_NAME=Admins 41 | - SERVER_ROLE_0_PASSWORD=secret1 42 | - SERVER_ROLE_0_CAN_KICK_BAN=true 43 | - SERVER_ROLE_0_CAN_ACCESS_INVENTORIES=true 44 | - SERVER_ROLE_0_CAN_EDIT_BASE=true 45 | - SERVER_ROLE_0_CAN_EXTEND_BASE=true 46 | - SERVER_ROLE_0_RESERVED_SLOTS=1 47 | - SERVER_ROLE_1_NAME=Friends 48 | - SERVER_ROLE_1_PASSWORD=secret2 49 | - SERVER_ROLE_1_CAN_ACCESS_INVENTORIES=true 50 | - SERVER_ROLE_1_CAN_EDIT_BASE=true 51 | - SERVER_ROLE_1_CAN_EXTEND_BASE=true 52 | - SERVER_ROLE_1_RESERVED_SLOTS=3 53 | - SERVER_ROLE_2_NAME=Guests 54 | - SERVER_ROLE_2_PASSWORD=secret3 55 | ``` 56 | 57 | Creates the following `enshrouded_server.json` file: 58 | 59 | ```json 60 | { 61 | "name": "Enshrouded Server", 62 | "password": "", 63 | "saveDirectory": "./savegame", 64 | "logDirectory": "./logs", 65 | "ip": "0.0.0.0", 66 | "queryPort": 15637, 67 | "slotCount": 16, 68 | "userGroups": [ 69 | { 70 | "name": "Admins", 71 | "password": "secret1", 72 | "canKickBan": true, 73 | "canAccessInventories": true, 74 | "canEditBase": true, 75 | "canExtendBase": true, 76 | "reservedSlots": 1 77 | }, 78 | { 79 | "name": "Friends", 80 | "password": "secret2", 81 | "canKickBan": false, 82 | "canAccessInventories": true, 83 | "canEditBase": true, 84 | "canExtendBase": true, 85 | "reservedSlots": 3 86 | }, 87 | { 88 | "name": "Guests", 89 | "password": "secret3", 90 | "canKickBan": false, 91 | "canAccessInventories": false, 92 | "canEditBase": false, 93 | "canExtendBase": false, 94 | "reservedSlots": 0 95 | } 96 | ] 97 | } 98 | ``` 99 | 100 |
-------------------------------------------------------------------------------- /scripts/default/bootstrap: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | . "$(dirname "$0")/common" 3 | . "$(dirname "$0")/defaults" 4 | 5 | main() { 6 | verifyVariables 7 | createFolders 8 | applyPermissions 9 | setupSyslog 10 | exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf 11 | } 12 | 13 | createFolders() { 14 | info "Creating server folders (save, logs, backup)" 15 | if [[ -n "$SERVER_SAVE_DIR" ]]; then 16 | if [[ "$SERVER_SAVE_DIR" == /* ]]; then 17 | mkdir -p "$SERVER_SAVE_DIR" 18 | else 19 | mkdir -p "$install_path/$SERVER_SAVE_DIR" 20 | fi 21 | fi 22 | 23 | if [[ -n "$SERVER_LOG_DIR" ]]; then 24 | if [[ "$SERVER_LOG_DIR" == /* ]]; then 25 | mkdir -p "$SERVER_LOG_DIR" 26 | else 27 | mkdir -p "$install_path/$SERVER_LOG_DIR" 28 | fi 29 | fi 30 | 31 | if [[ -n "$BACKUP_CRON" ]] && [[ -n "$BACKUP_DIR" ]]; then 32 | if [[ "$BACKUP_DIR" == /* ]]; then 33 | mkdir -p "$BACKUP_DIR" 34 | else 35 | mkdir -p "$install_path/$BACKUP_DIR" 36 | fi 37 | fi 38 | } 39 | 40 | # Apply user id and group id 41 | applyPermissions() { 42 | info "Setting uid:gid of enshrouded to $PUID:$PGID" 43 | groupmod -g "${PGID}" -o enshrouded 44 | usermod -u "${PUID}" -o enshrouded 45 | sed -i -E "s/^(enshrouded:x):[0-9]+:[0-9]+:(.*)/\\1:$PUID:$PGID:\\2/" /etc/passwd 46 | 47 | chown -R enshrouded:enshrouded \ 48 | /opt/enshrouded \ 49 | /home/enshrouded \ 50 | /var/run/enshrouded 51 | 52 | if [[ "$SERVER_SAVE_DIR" == /* ]]; then 53 | debug "Setting permissions for $SERVER_SAVE_DIR" 54 | chown -R enshrouded:enshrouded "$SERVER_SAVE_DIR" 55 | fi 56 | 57 | if [[ "$SERVER_LOG_DIR" == /* ]]; then 58 | debug "Setting permissions for $SERVER_LOG_DIR" 59 | chown -R enshrouded:enshrouded "$SERVER_LOG_DIR" 60 | fi 61 | 62 | if [[ "$BACKUP_DIR" == /* ]]; then 63 | debug "Setting permissions for $BACKUP_DIR" 64 | chown -R enshrouded:enshrouded "$BACKUP_DIR" 65 | fi 66 | 67 | chgrp enshrouded /etc/supervisor/supervisord.conf 68 | } 69 | 70 | # Configure syslog 71 | setupSyslog() { 72 | info "Setting up syslogd - logging to stdout" 73 | 74 | cat >"$rsyslog_conf" <"$supervisor_syslog_conf" <&2 63 | } 64 | 65 | printline() { 66 | local log_at_level 67 | local log_data 68 | log_at_level="$1" 69 | shift 70 | log_data="$*" 71 | 72 | if [ "$log_at_level" -le "$log_level" ]; then 73 | echo "$log_data" 74 | fi 75 | } 76 | 77 | checkLock() { 78 | local pidfile 79 | local predecessor_pid 80 | local numre 81 | pidfile=$1 82 | predecessor_pid=$(<"$pidfile") 83 | numre='^[0-9]+$' 84 | if [[ "$predecessor_pid" =~ $numre ]]; then 85 | debug "Sending SIGUSR1 to PID $predecessor_pid" 86 | if kill -USR1 "$predecessor_pid" &>/dev/null; then 87 | fatal "Process with PID $predecessor_pid already running - exiting" 88 | else 89 | info "Removing stale PID file and starting run" 90 | clearLockAndRun "$pidfile" 91 | fi 92 | else 93 | warn "Predecessor PID is corrupt - clearing lock and running" 94 | clearLockAndRun "$pidfile" 95 | fi 96 | } 97 | 98 | clearLockAndRun() { 99 | local pidfile 100 | pidfile=$1 101 | clearLock "$pidfile" 102 | main 103 | } 104 | 105 | clearLock() { 106 | local pidfile 107 | pidfile=$1 108 | info "Releasing PID file $pidfile" 109 | kill -SIGTERM $pidfile 2>/dev/null 110 | rm -f "$1" 111 | } 112 | 113 | checkRunning() { 114 | local proc 115 | local status 116 | proc=$1 117 | status=$(supervisorctl status "${proc}" 2>&1) 118 | if [[ "$status" == *RUNNING* ]]; then 119 | return 0 120 | else 121 | return 1 122 | fi 123 | } 124 | -------------------------------------------------------------------------------- /scripts/default/defaults: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Server Settings 4 | SERVER_NAME=${SERVER_NAME} # defaults to Enshrouded Server 5 | SERVER_PASSWORD=${SERVER_PASSWORD} 6 | SERVER_SLOT_COUNT=${SERVER_SLOT_COUNT} # defaults to 16 7 | SERVER_PORT=${SERVER_PORT} # defaults to 15636 8 | SERVER_QUERYPORT=${SERVER_QUERYPORT} # defaults to 15637 9 | SERVER_IP=${SERVER_IP} # defaults to 0.0.0.0 10 | SERVER_SAVE_DIR=${SERVER_SAVE_DIR} # defaults to ./savegame 11 | SERVER_LOG_DIR=${SERVER_LOG_DIR} # defaults to ./logs 12 | 13 | # Steam Settings 14 | GAME_BRANCH=${GAME_BRANCH:-public} 15 | STEAMCMD_ARGS=${STEAMCMD_ARGS:-"$GAME_BRANCH" validate} 16 | 17 | # Update 18 | UPDATE_CRON=${UPDATE_CRON:-} 19 | UPDATE_CHECK_PLAYERS=${UPDATE_CHECK_PLAYERS:-false} 20 | 21 | # Backup 22 | BACKUP_CRON=${BACKUP_CRON:-} 23 | BACKUP_DIR=${BACKUP_DIR:-backups} 24 | BACKUP_MAX_COUNT=${BACKUP_MAX_COUNT:-0} 25 | 26 | # Hooks 27 | BOOTSTRAP_HOOK=${BOOTSTRAP_HOOK:-} 28 | UPDATE_PRE_HOOK=${UPDATE_PRE_HOOK:-} 29 | UPDATE_POST_HOOK=${UPDATE_POST_HOOK:-} 30 | BACKUP_PRE_HOOK=${BACKUP_PRE_HOOK:-} 31 | BACKUP_POST_HOOK=${BACKUP_POST_HOOK:-} 32 | 33 | # MISC 34 | PUID=${PUID:-4711} 35 | PGID=${PGID:-4711} 36 | 37 | # WINE 38 | WINEDEBUG=${WINEDEBUG:-fixme-all} 39 | 40 | 41 | -------------------------------------------------------------------------------- /scripts/default/enshrouded-backup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | . "$(dirname "$0")/common" 3 | . "$(dirname "$0")/defaults" 4 | 5 | pidfile=$enshrouded_backup_pidfile 6 | save_dir="" 7 | backup_dir="" 8 | 9 | main() { 10 | info "Running enshrouded-backup" 11 | prepareBackup 12 | info "enshrouded-backup complete" 13 | } 14 | 15 | prepareBackup() { 16 | if [ -f "$pidfile" ]; then 17 | info "Found existing PID file - checking process" 18 | checkLock $pidfile 19 | fi 20 | 21 | getSaveDir 22 | getBackupDir 23 | 24 | if [ ! -f "$save_dir/$savefile_name-index" ]; then 25 | warn "Save file not found - aborting backup" 26 | return 27 | fi 28 | 29 | trap shutdown SIGINT SIGTERM 30 | 31 | backupAndCleanup & 32 | enshrouded_backup_pid=$! 33 | echo $enshrouded_backup_pid >"$pidfile" 34 | wait $enshrouded_backup_pid 35 | } 36 | 37 | backupAndCleanup() { 38 | backup 39 | cleanup 40 | backupPostHook 41 | clearLock "$pidfile" 42 | } 43 | 44 | backup() { 45 | local latest_save_index latest_savefile_name backup_file_name 46 | debug "run backup" 47 | 48 | # parse 3ad85aea-index (json) to get latest save file 49 | latest_save_index=$(jq -r '.latest' "$save_dir/$savefile_name-index") 50 | 51 | # if index = 0 save game is just $savefile_name otherwise $savefile_name-$index 52 | if [ "$latest_save_index" -eq 0 ]; then 53 | latest_savefile_name="$savefile_name" 54 | else 55 | latest_savefile_name="$savefile_name-$latest_save_index" 56 | fi 57 | 58 | # check if latest save file exists 59 | if [ ! -f "$save_dir/$latest_savefile_name" ]; then 60 | warn "Latest save file not found - aborting backup" 61 | return 62 | fi 63 | 64 | backupPreHook 65 | 66 | # create new index file 67 | cat > /tmp/$savefile_name-index </dev/null 2>&1" >>"$crontab" 15 | fi 16 | 17 | if [ -n "$BACKUP_CRON" ]; then 18 | debug "creating cron for backups (schedule: $BACKUP_CRON)" 19 | echo "$BACKUP_CRON supervisorctl start enshrouded-backup >/dev/null 2>&1" >>"$crontab" 20 | fi 21 | 22 | crontab "$crontab" 23 | rm -f "$crontab" 24 | } 25 | 26 | prepareSteamA2sPythonLibrary() { 27 | pip3 install python-a2s==1.3.0 --break-system-packages 28 | } 29 | 30 | bootstrapHook() { 31 | if [ -n "$BOOTSTRAP_HOOK" ]; then 32 | info "Running bootstrap hook: $BOOTSTRAP_HOOK" 33 | eval "$BOOTSTRAP_HOOK" 34 | fi 35 | } 36 | 37 | updateOrCreateEnshroudedServerConfig() { 38 | if [[ ! -e ${install_path}/enshrouded_server.json ]]; then 39 | mkdir -p ${install_path} 40 | touch ${install_path}/enshrouded_server.json 41 | 42 | # write json to file ${install_path}/enshrouded_server.json 43 | 44 | cat >${install_path}/enshrouded_server.json << EOF 45 | { 46 | "name": "Enshrouded Server", 47 | "saveDirectory": "./savegame", 48 | "logDirectory": "./logs", 49 | "ip": "0.0.0.0", 50 | "queryPort": 15637, 51 | "slotCount": 16, 52 | "voiceChatMode": "Proximity", 53 | "enableVoiceChat": false, 54 | "enableTextChat": false 55 | } 56 | EOF 57 | fi 58 | 59 | if [[ -n "$SERVER_NAME" ]]; then 60 | debug "updating name to $SERVER_NAME" 61 | echo "$(jq --arg name "$SERVER_NAME" '.name = $name' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 62 | fi 63 | 64 | if [[ -n "$SERVER_SAVE_DIR" ]]; then 65 | debug "updating saveDirectory to $SERVER_SAVE_DIR" 66 | echo "$(jq --arg saveDirectory "$SERVER_SAVE_DIR" '.saveDirectory = $saveDirectory' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 67 | fi 68 | 69 | if [[ -n "$SERVER_LOG_DIR" ]]; then 70 | debug "updating logDirectory to $SERVER_LOG_DIR" 71 | echo "$(jq --arg logDirectory "$SERVER_LOG_DIR" '.logDirectory = $logDirectory' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 72 | fi 73 | 74 | if [[ -n "$SERVER_IP" ]]; then 75 | debug "updating ip to $SERVER_IP" 76 | echo "$(jq --arg ip "$SERVER_IP" '.ip = $ip' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 77 | fi 78 | 79 | if [[ -n "$SERVER_QUERYPORT" ]]; then 80 | debug "updating queryPort to $SERVER_QUERYPORT" 81 | echo "$(jq --argjson queryPort "$SERVER_QUERYPORT" '.queryPort = $queryPort' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 82 | fi 83 | 84 | if [[ -n "$SERVER_SLOT_COUNT" ]]; then 85 | debug "updating slotCount to $SERVER_SLOT_COUNT" 86 | echo "$(jq --argjson slotCount "$SERVER_SLOT_COUNT" '.slotCount = $slotCount' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 87 | fi 88 | 89 | if [[ -n "$SERVER_VOICE_CHAT_MODE" ]]; then 90 | debug "updating voiceChatMode to $SERVER_VOICE_CHAT_MODE" 91 | echo "$(jq --arg voiceChatMode "$SERVER_VOICE_CHAT_MODE" '.voiceChatMode = $voiceChatMode' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 92 | fi 93 | 94 | if [[ -n "$SERVER_ENABLE_VOICE_CHAT" ]]; then 95 | debug "updating enableVoiceChat to $SERVER_ENABLE_VOICE_CHAT" 96 | echo "$(jq --argjson enableVoiceChat "$SERVER_ENABLE_VOICE_CHAT" '.enableVoiceChat = $enableVoiceChat' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 97 | fi 98 | 99 | if [[ -n "$SERVER_ENABLE_TEXT_CHAT" ]]; then 100 | debug "updating enableTextChat to $SERVER_ENABLE_TEXT_CHAT" 101 | echo "$(jq --argjson enableTextChat "$SERVER_ENABLE_TEXT_CHAT" '.enableTextChat = $enableTextChat' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 102 | fi 103 | 104 | updateUserGroupConfig 105 | updateGameSettingsConfig 106 | } 107 | 108 | updateUserGroupConfig() { 109 | local group_count group_index group_param group_value 110 | # get largest group index of env vars 111 | group_count=$(compgen -A variable | grep -E "^SERVER_ROLE_[0-9]+_" | cut -d'_' -f3 | sort -nr | head -n1) 112 | 113 | # check if userGroups array exists if not create empty array 114 | if ! jq -e 'has("userGroups")' ${install_path}/enshrouded_server.json >/dev/null; then 115 | debug "userGroups array does not exist, creating empty array" 116 | echo "$(jq '.userGroups = []' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 117 | fi 118 | 119 | handleDeprecatedServerPassword 120 | 121 | # add missing groups 122 | for group_index in $(seq 0 $group_count); do 123 | if ! jq -e --argjson group_index "$group_index" '.userGroups | has($group_index)' ${install_path}/enshrouded_server.json >/dev/null; then 124 | debug "group $group_index does not exist, creating default group" 125 | echo "$(jq --argjson group_index "$group_index" '.userGroups += [{"name": "Default", "password": "", "canKickBan": false, "canAccessInventories": false, "canEditBase": false, "canExtendBase": false, "reservedSlots": 0}]' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 126 | fi 127 | done 128 | 129 | for i in $(compgen -A variable | grep -E "^SERVER_ROLE_[0-9]+_"); do 130 | group_index=$(echo $i | cut -d'_' -f3) 131 | group_param=$(echo $i | cut -d'_' -f4-) 132 | group_value=$(eval echo \$$i) 133 | 134 | case $group_param in 135 | NAME) 136 | debug "updating group $group_index name to $group_value" 137 | echo "$(jq --argjson group_index "$group_index" --arg name "$group_value" '.userGroups[$group_index].name = $name' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 138 | ;; 139 | PASSWORD) 140 | debug "updating group $group_index password to $group_value" 141 | echo "$(jq --argjson group_index "$group_index" --arg password "$group_value" '.userGroups[$group_index].password = $password' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 142 | ;; 143 | CAN_KICK_BAN) 144 | debug "updating group $group_index canKickBan to $group_value" 145 | echo "$(jq --argjson group_index "$group_index" --argjson canKickBan "$group_value" '.userGroups[$group_index].canKickBan = $canKickBan' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 146 | ;; 147 | CAN_ACCESS_INVENTORIES) 148 | debug "updating group $group_index canAccessInventories to $group_value" 149 | echo "$(jq --argjson group_index "$group_index" --argjson canAccessInventories "$group_value" '.userGroups[$group_index].canAccessInventories = $canAccessInventories' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 150 | ;; 151 | CAN_EDIT_BASE) 152 | debug "updating group $group_index canEditBase to $group_value" 153 | echo "$(jq --argjson group_index "$group_index" --argjson canEditBase "$group_value" '.userGroups[$group_index].canEditBase = $canEditBase' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 154 | ;; 155 | CAN_EXTEND_BASE) 156 | debug "updating group $group_index canExtendBase to $group_value" 157 | echo "$(jq --argjson group_index "$group_index" --argjson canExtendBase "$group_value" '.userGroups[$group_index].canExtendBase = $canExtendBase' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 158 | ;; 159 | RESERVED_SLOTS) 160 | debug "updating group $group_index reservedSlots to $group_value" 161 | echo "$(jq --argjson group_index "$group_index" --argjson reservedSlots "$group_value" '.userGroups[$group_index].reservedSlots = $reservedSlots' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 162 | ;; 163 | esac 164 | done 165 | } 166 | 167 | handleDeprecatedServerPassword() { 168 | if [[ -n "$SERVER_PASSWORD" ]]; then 169 | warn "SERVER_PASSWORD is deprecated, pls consider using SERVER_ROLE__PASSWORD instead" 170 | warn "falling back to \"Default\" server role password" 171 | 172 | # check if group 0 exists if not create it 173 | if ! jq -e '.userGroups[0]' ${install_path}/enshrouded_server.json >/dev/null; then 174 | debug "default group (index: 0) does not exist, creating default group." 175 | echo "$(jq --argjson group_index "$group_index" '.userGroups += [{"name": "Default", "password": "", "canKickBan": false, "canAccessInventories": false, "canEditBase": false, "canExtendBase": false, "reservedSlots": 0}]' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 176 | fi 177 | 178 | # check if group 0 name is "Default" if not return 179 | if [[ "$(jq -r '.userGroups[0].name' ${install_path}/enshrouded_server.json)" != "Default" ]]; then 180 | warn "default group (index: 0) has not the name \"Default\". Skipping password update!" 181 | return 182 | fi 183 | 184 | debug "updating default group (index: 0) password to $SERVER_PASSWORD" 185 | echo "$(jq --arg password "$SERVER_PASSWORD" '.userGroups[0].password = $password' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 186 | fi 187 | } 188 | 189 | updateGameSettingsConfig() { 190 | if [[ -n "$SERVER_GS_PRESET" ]]; then 191 | debug "updating gameSettingsPreset to $SERVER_GS_PRESET" 192 | echo "$(jq --arg name "$SERVER_GS_PRESET" '.gameSettingsPreset = $name' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 193 | fi 194 | 195 | if [[ -n "$SERVER_GS_PLAYER_HEALTH_FACTOR" ]]; then 196 | debug "updating gameSettingsPlayerHealthFactor to $SERVER_GS_PLAYER_HEALTH_FACTOR" 197 | echo "$(jq --argjson factor "$SERVER_GS_PLAYER_HEALTH_FACTOR" '.gameSettings.playerHealthFactor = $factor' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 198 | fi 199 | 200 | if [[ -n "$SERVER_GS_PLAYER_MANA_FACTOR" ]]; then 201 | debug "updating gameSettingsPlayerManaFactor to $SERVER_GS_PLAYER_MANA_FACTOR" 202 | echo "$(jq --argjson factor "$SERVER_GS_PLAYER_MANA_FACTOR" '.gameSettings.playerManaFactor = $factor' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 203 | fi 204 | 205 | if [[ -n "$SERVER_GS_PLAYER_STAMINA_FACTOR" ]]; then 206 | debug "updating gameSettingsPlayerStaminaFactor to $SERVER_GS_PLAYER_STAMINA_FACTOR" 207 | echo "$(jq --argjson factor "$SERVER_GS_PLAYER_STAMINA_FACTOR" '.gameSettings.playerStaminaFactor = $factor' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 208 | fi 209 | 210 | if [[ -n "$SERVER_GS_PLAYER_BODY_HEAT_FACTOR" ]]; then 211 | debug "updating gameSettingsPlayerBodyHeatFactor to $SERVER_GS_PLAYER_BODY_HEAT_FACTOR" 212 | echo "$(jq --argjson factor "$SERVER_GS_PLAYER_BODY_HEAT_FACTOR" '.gameSettings.playerBodyHeatFactor = $factor' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 213 | fi 214 | 215 | if [[ -n "$SERVER_GS_ENABLE_DURABILITY" ]]; then 216 | debug "updating gameSettingsEnableDurability to $SERVER_GS_ENABLE_DURABILITY" 217 | echo "$(jq --argjson bool "$SERVER_GS_ENABLE_DURABILITY" '.gameSettings.enableDurability = $bool' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 218 | fi 219 | 220 | if [[ -n "$SERVER_GS_ENABLE_STARVING_DEBUFF" ]]; then 221 | debug "updating gameSettingsEnableStarvingDebuff to $SERVER_GS_ENABLE_STARVING_DEBUFF" 222 | echo "$(jq --argjson bool "$SERVER_GS_ENABLE_STARVING_DEBUFF" '.gameSettings.enableStarvingDebuff = $bool' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 223 | fi 224 | 225 | if [[ -n "$SERVER_GS_FOOD_BUFF_DURATION_FACTOR" ]]; then 226 | debug "updating gameSettingsFoodBuffDurationFactor to $SERVER_GS_FOOD_BUFF_DURATION_FACTOR" 227 | echo "$(jq --argjson factor "$SERVER_GS_FOOD_BUFF_DURATION_FACTOR" '.gameSettings.foodBuffDurationFactor = $factor' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 228 | fi 229 | 230 | if [[ -n "$SERVER_GS_FROM_HUNGER_TO_STARVING" ]]; then 231 | debug "updating gameSettingsFromHungerToStarving to $SERVER_GS_FROM_HUNGER_TO_STARVING" 232 | echo "$(jq --argjson factor "$SERVER_GS_FROM_HUNGER_TO_STARVING" '.gameSettings.fromHungerToStarving = $factor' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 233 | fi 234 | 235 | if [[ -n "$SERVER_GS_SHROUD_TIME_FACTOR" ]]; then 236 | debug "updating gameSettingsShroudTimeFactor to $SERVER_GS_SHROUD_TIME_FACTOR" 237 | echo "$(jq --argjson factor "$SERVER_GS_SHROUD_TIME_FACTOR" '.gameSettings.shroudTimeFactor = $factor' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 238 | fi 239 | 240 | if [[ -n "$SERVER_GS_ENABLE_GLIDER_TURBULENCES" ]]; then 241 | debug "updating gameSettingsEnableGliderTurbulences to $SERVER_GS_ENABLE_GLIDER_TURBULENCES" 242 | echo "$(jq --argjson bool "$SERVER_GS_ENABLE_GLIDER_TURBULENCES" '.gameSettings.enableGliderTurbulences = $bool' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 243 | fi 244 | 245 | if [[ -n "$SERVER_GS_WEATHER_FREQUENCY" ]]; then 246 | debug "updating gameSettingsWeatherFrequency to $SERVER_GS_WEATHER_FREQUENCY" 247 | echo "$(jq --arg name "$SERVER_GS_WEATHER_FREQUENCY" '.gameSettings.weatherFrequency = $name' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 248 | fi 249 | 250 | if [[ -n "$SERVER_GS_RANDOM_SPAWNER_AMOUNT" ]]; then 251 | debug "updating gameSettingsRandomSpawnerAmount to $SERVER_GS_RANDOM_SPAWNER_AMOUNT" 252 | echo "$(jq --arg name "$SERVER_GS_RANDOM_SPAWNER_AMOUNT" '.gameSettings.randomSpawnerAmount = $name' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 253 | fi 254 | 255 | if [[ -n "$SERVER_GS_MINING_DAMAGE_FACTOR" ]]; then 256 | debug "updating gameSettingsMiningDamageFactor to $SERVER_GS_MINING_DAMAGE_FACTOR" 257 | echo "$(jq --argjson factor "$SERVER_GS_MINING_DAMAGE_FACTOR" '.gameSettings.miningDamageFactor = $factor' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 258 | fi 259 | 260 | if [[ -n "$SERVER_GS_PLANT_GROWTH_SPEED_FACTOR" ]]; then 261 | debug "updating gameSettingsPlantGrowthSpeedFactor to $SERVER_GS_PLANT_GROWTH_SPEED_FACTOR" 262 | echo "$(jq --argjson factor "$SERVER_GS_PLANT_GROWTH_SPEED_FACTOR" '.gameSettings.plantGrowthSpeedFactor = $factor' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 263 | fi 264 | 265 | if [[ -n "$SERVER_GS_RESOURCE_DROP_STACK_AMOUNT_FACTOR" ]]; then 266 | debug "updating gameSettingsResourceDropStackAmountFactor to $SERVER_GS_RESOURCE_DROP_STACK_AMOUNT_FACTOR" 267 | echo "$(jq --argjson factor "$SERVER_GS_RESOURCE_DROP_STACK_AMOUNT_FACTOR" '.gameSettings.resourceDropStackAmountFactor = $factor' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 268 | fi 269 | 270 | if [[ -n "$SERVER_GS_FACTORY_PRODUCTION_SPEED_FACTOR" ]]; then 271 | debug "updating gameSettingsFactoryProductionSpeedFactor to $SERVER_GS_FACTORY_PRODUCTION_SPEED_FACTOR" 272 | echo "$(jq --argjson factor "$SERVER_GS_FACTORY_PRODUCTION_SPEED_FACTOR" '.gameSettings.factoryProductionSpeedFactor = $factor' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 273 | fi 274 | 275 | if [[ -n "$SERVER_GS_PERK_UPGRADE_RECYCLING_FACTOR" ]]; then 276 | debug "updating gameSettingsPerkUpgradeRecyclingFactor to $SERVER_GS_PERK_UPGRADE_RECYCLING_FACTOR" 277 | echo "$(jq --argjson factor "$SERVER_GS_PERK_UPGRADE_RECYCLING_FACTOR" '.gameSettings.perkUpgradeRecyclingFactor = $factor' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 278 | fi 279 | 280 | if [[ -n "$SERVER_GS_PERK_COST_FACTOR" ]]; then 281 | debug "updating gameSettingsPerkCostFactor to $SERVER_GS_PERK_COST_FACTOR" 282 | echo "$(jq --argjson factor "$SERVER_GS_PERK_COST_FACTOR" '.gameSettings.perkCostFactor = $factor' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 283 | fi 284 | 285 | if [[ -n "$SERVER_GS_EXPERIENCE_COMBAT_FACTOR" ]]; then 286 | debug "updating gameSettingsExperienceCombatFactor to $SERVER_GS_EXPERIENCE_COMBAT_FACTOR" 287 | echo "$(jq --argjson factor "$SERVER_GS_EXPERIENCE_COMBAT_FACTOR" '.gameSettings.experienceCombatFactor = $factor' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 288 | fi 289 | 290 | if [[ -n "$SERVER_GS_EXPERIENCE_MINING_FACTOR" ]]; then 291 | debug "updating gameSettingsExperienceMiningFactor to $SERVER_GS_EXPERIENCE_MINING_FACTOR" 292 | echo "$(jq --argjson factor "$SERVER_GS_EXPERIENCE_MINING_FACTOR" '.gameSettings.experienceMiningFactor = $factor' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 293 | fi 294 | 295 | if [[ -n "$SERVER_GS_EXPERIENCE_EXPLORATION_QUESTS_FACTOR" ]]; then 296 | debug "updating gameSettingsExperienceExplorationQuestsFactor to $SERVER_GS_EXPERIENCE_EXPLORATION_QUESTS_FACTOR" 297 | echo "$(jq --argjson factor "$SERVER_GS_EXPERIENCE_EXPLORATION_QUESTS_FACTOR" '.gameSettings.experienceExplorationQuestsFactor = $factor' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 298 | fi 299 | 300 | if [[ -n "$SERVER_GS_AGGRO_POOL_AMOUNT" ]]; then 301 | debug "updating gameSettingsAggroPoolAmount to $SERVER_GS_AGGRO_POOL_AMOUNT" 302 | echo "$(jq --arg name "$SERVER_GS_AGGRO_POOL_AMOUNT" '.gameSettings.aggroPoolAmount = $name' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 303 | fi 304 | 305 | if [[ -n "$SERVER_GS_ENEMY_DAMAGE_FACTOR" ]]; then 306 | debug "updating gameSettingsEnemyDamageFactor to $SERVER_GS_ENEMY_DAMAGE_FACTOR" 307 | echo "$(jq --argjson factor "$SERVER_GS_ENEMY_DAMAGE_FACTOR" '.gameSettings.enemyDamageFactor = $factor' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 308 | fi 309 | 310 | if [[ -n "$SERVER_GS_ENEMY_HEALTH_FACTOR" ]]; then 311 | debug "updating gameSettingsEnemyHealthFactor to $SERVER_GS_ENEMY_HEALTH_FACTOR" 312 | echo "$(jq --argjson factor "$SERVER_GS_ENEMY_HEALTH_FACTOR" '.gameSettings.enemyHealthFactor = $factor' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 313 | fi 314 | 315 | if [[ -n "$SERVER_GS_ENEMY_STAMINA_FACTOR" ]]; then 316 | debug "updating gameSettingsEnemyStaminaFactor to $SERVER_GS_ENEMY_STAMINA_FACTOR" 317 | echo "$(jq --argjson factor "$SERVER_GS_ENEMY_STAMINA_FACTOR" '.gameSettings.enemyStaminaFactor = $factor' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 318 | fi 319 | 320 | if [[ -n "$SERVER_GS_ENEMY_PERCEPTION_RANGE_FACTOR" ]]; then 321 | debug "updating gameSettingsEnemyPerceptionRangeFactor to $SERVER_GS_ENEMY_PERCEPTION_RANGE_FACTOR" 322 | echo "$(jq --argjson factor "$SERVER_GS_ENEMY_PERCEPTION_RANGE_FACTOR" '.gameSettings.enemyPerceptionRangeFactor = $factor' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 323 | fi 324 | 325 | if [[ -n "$SERVER_GS_BOSS_DAMAGE_FACTOR" ]]; then 326 | debug "updating gameSettingsBossDamageFactor to $SERVER_GS_BOSS_DAMAGE_FACTOR" 327 | echo "$(jq --argjson factor "$SERVER_GS_BOSS_DAMAGE_FACTOR" '.gameSettings.bossDamageFactor = $factor' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 328 | fi 329 | 330 | if [[ -n "$SERVER_GS_BOSS_HEALTH_FACTOR" ]]; then 331 | debug "updating gameSettingsBossHealthFactor to $SERVER_GS_BOSS_HEALTH_FACTOR" 332 | echo "$(jq --argjson factor "$SERVER_GS_BOSS_HEALTH_FACTOR" '.gameSettings.bossHealthFactor = $factor' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 333 | fi 334 | 335 | if [[ -n "$SERVER_GS_THREAT_BONUS" ]]; then 336 | debug "updating gameSettingsThreatBonus to $SERVER_GS_THREAT_BONUS" 337 | echo "$(jq --argjson factor "$SERVER_GS_THREAT_BONUS" '.gameSettings.threatBonus = $factor' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 338 | fi 339 | 340 | if [[ -n "$SERVER_GS_PACIFY_ALL_ENEMIES" ]]; then 341 | debug "updating gameSettingsPacifyAllEnemies to $SERVER_GS_PACIFY_ALL_ENEMIES" 342 | echo "$(jq --argjson bool "$SERVER_GS_PACIFY_ALL_ENEMIES" '.gameSettings.pacifyAllEnemies = $bool' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 343 | fi 344 | 345 | if [[ -n "$SERVER_GS_TAMING_STARTLE_REPERCUSSION" ]]; then 346 | debug "updating gameSettingsTamingStartleRepercussion to $SERVER_GS_TAMING_STARTLE_REPERCUSSION" 347 | echo "$(jq --arg name "$SERVER_GS_TAMING_STARTLE_REPERCUSSION" '.gameSettings.tamingStartleRepercussion = $name' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 348 | fi 349 | 350 | if [[ -n "$SERVER_GS_DAY_TIME_DURATION" ]]; then 351 | debug "updating gameSettingsDayTimeDuration to $SERVER_GS_DAY_TIME_DURATION" 352 | echo "$(jq --argjson factor "$SERVER_GS_DAY_TIME_DURATION" '.gameSettings.dayTimeDuration = $factor' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 353 | fi 354 | 355 | if [[ -n "$SERVER_GS_NIGHT_TIME_DURATION" ]]; then 356 | debug "updating gameSettingsNightTimeDuration to $SERVER_GS_NIGHT_TIME_DURATION" 357 | echo "$(jq --argjson factor "$SERVER_GS_NIGHT_TIME_DURATION" '.gameSettings.nightTimeDuration = $factor' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 358 | fi 359 | 360 | if [[ -n "$SERVER_GS_TOMBSTONE_MODE" ]]; then 361 | debug "updating gameSettingsTombstoneMode to $SERVER_GS_TOMBSTONE_MODE" 362 | echo "$(jq --arg name "$SERVER_GS_TOMBSTONE_MODE" '.gameSettings.tombstoneMode = $name' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 363 | fi 364 | } 365 | -------------------------------------------------------------------------------- /scripts/default/enshrouded-force-update: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | . "$(dirname "$0")/common" 3 | . "$(dirname "$0")/defaults" 4 | 5 | main() { 6 | info "Force Enshrouded update" 7 | rm -f $version_file_path 8 | 9 | # Remove steamapp manifests to solve steamcmd update issues #119 10 | debug "Removing $install_path/$steamapp_path" 11 | rm -rf $install_path/$steamapp_path 12 | 13 | supervisorctl start enshrouded-updater 14 | } 15 | 16 | main 17 | -------------------------------------------------------------------------------- /scripts/default/enshrouded-reset-roles: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | . "$(dirname "$0")/common" 3 | . "$(dirname "$0")/defaults" 4 | 5 | main() { 6 | info "Stopping enshrouded server" 7 | supervisorctl stop enshrouded-server 8 | 9 | info "Reset enshrouded server roles" 10 | echo "$(jq 'del(.userGroups)' ${install_path}/enshrouded_server.json)" > ${install_path}/enshrouded_server.json 11 | 12 | info "Stop container for a clean start" 13 | kill -INT $(cat /var/run/supervisord.pid) 14 | } 15 | 16 | main 17 | -------------------------------------------------------------------------------- /scripts/default/enshrouded-updater-shared: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | . "$(dirname "$0")/common" 3 | . "$(dirname "$0")/defaults" 4 | 5 | pidfile=$enshrouded_updater_pidfile 6 | latest_version=-1 7 | 8 | update() { 9 | if [ -f "$pidfile" ]; then 10 | info "Found existing PID file - checking process" 11 | checkLock $pidfile 12 | fi 13 | trap shutdown SIGINT SIGTERM 14 | if ! checkForUpdates; then 15 | if ! checkRunning "enshrouded-server"; then 16 | info "Enshrouded server is not running - starting" 17 | supervisorctl start enshrouded-server 18 | fi 19 | return 20 | fi 21 | if ! checkServerEmpty; then 22 | warn "Enshrouded server is not empty - update will not be performed" 23 | return 24 | fi 25 | 26 | doUpdate & 27 | enshrouded_updater_pid=$! 28 | echo $enshrouded_updater_pid >"$pidfile" 29 | wait $enshrouded_updater_pid 30 | } 31 | 32 | doUpdate() { 33 | updatePreHook 34 | if checkRunning "enshrouded-server"; then 35 | supervisorctl stop enshrouded-server 36 | fi 37 | verifyCpuMhz 38 | if ! downloadEnshrouded; then 39 | warn "Download of Enshrouded server failed - aborting update" 40 | supervisorctl start enshrouded-server 41 | clearLock "$pidfile" 42 | return 43 | fi 44 | setCurrentVersion 45 | supervisorctl start enshrouded-server 46 | updatePostHook 47 | 48 | clearLock "$pidfile" 49 | } 50 | 51 | # This works around the `Unable to determine CPU Frequency. Try defining CPU_MHZ.` steamcmd issue. 52 | verifyCpuMhz() { 53 | local float_regex 54 | local cpu_mhz 55 | float_regex="^([0-9]+\\.?[0-9]*)\$" 56 | cpu_mhz=$(grep "^cpu MHz" /proc/cpuinfo | head -1 | cut -d : -f 2 | xargs) 57 | if [ -n "$cpu_mhz" ] && [[ "$cpu_mhz" =~ $float_regex ]] && [ "${cpu_mhz%.*}" -gt 0 ]; then 58 | debug "Found CPU with $cpu_mhz MHz" 59 | unset CPU_MHZ 60 | else 61 | debug "Unable to determine CPU Frequency - setting a default of 1.5 GHz so steamcmd won't complain" 62 | export CPU_MHZ="1500.000" 63 | fi 64 | } 65 | 66 | checkServerEmpty() { 67 | local connected_players 68 | 69 | if [ -n "$STEAM_API_PUBLIC_IP" ] && [ -n "$STEAM_API_KEY" ]; then 70 | warn "STEAM_API_PUBLIC_IP and STEAM_API_KEY are deprecated and will be removed in a future release" 71 | else 72 | if [ "$UPDATE_CHECK_PLAYERS" == "false" ]; then 73 | return 0 74 | fi 75 | fi 76 | 77 | connected_players=$(python3 -c " 78 | try: 79 | import a2s 80 | print(len(a2s.players(('127.0.0.1',${SERVER_QUERYPORT:-15637})))) 81 | except Exception as e: 82 | print('null') 83 | ") 84 | 85 | debug "[checkServerEmpty] connected_players: $connected_players" 86 | if [ -n "$connected_players" ] && [ "$connected_players" != "null" ] && [ "$connected_players" -gt 0 ]; then 87 | return 1 88 | fi 89 | 90 | return 0 91 | } 92 | 93 | setCurrentVersion() { 94 | if [ "$latest_version" == "null" ] || [ "$latest_version" == "-1" ]; then 95 | warn "Unable to set current version - latest version is unknown" 96 | warn "Next update check will restart the server until version can be determined" 97 | return 1 98 | fi 99 | debug "[setCurrentVersion]: $latest_version" 100 | echo "$latest_version" >"$version_file_path" 101 | } 102 | 103 | updatePreHook() { 104 | if [ -n "$UPDATE_PRE_HOOK" ]; then 105 | info "Running update pre hook: $UPDATE_PRE_HOOK" 106 | eval "$UPDATE_PRE_HOOK" 107 | fi 108 | } 109 | 110 | updatePostHook() { 111 | if [ -n "$UPDATE_POST_HOOK" ]; then 112 | info "Running update post hook: $UPDATE_POST_HOOK" 113 | eval "$UPDATE_POST_HOOK" 114 | fi 115 | } 116 | 117 | shutdown() { 118 | debug "Received signal to shut down enshrouded-updater" 119 | clearLock "$pidfile" 120 | } 121 | -------------------------------------------------------------------------------- /scripts/proton/enshrouded-bootstrap: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | . "$(dirname "$0")/common" 3 | . "$(dirname "$0")/defaults" 4 | . "$(dirname "$0")/enshrouded-bootstrap-shared" 5 | 6 | main() { 7 | info "Running enshrouded-bootstrap" 8 | prepareEnshroudedAppFolders 9 | updateOrCreateEnshroudedServerConfig 10 | prepareSteamA2sPythonLibrary 11 | 12 | # no proton bootstrap needed 13 | 14 | initCrontab 15 | bootstrapHook 16 | supervisorctl start enshrouded-updater 17 | info "Bootstrap complete" 18 | } 19 | 20 | main 21 | -------------------------------------------------------------------------------- /scripts/proton/enshrouded-server: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | . "$(dirname "$0")/common" 3 | . "$(dirname "$0")/defaults" 4 | 5 | enshrouded_server_pid=-1 6 | timeout=60 7 | kill_signal=TERM 8 | 9 | cd "$install_path" || fatal "Could not cd $install_path" 10 | enshrouded_server="$install_path/$enshrouded_binary_path" 11 | 12 | main() { 13 | waitForServerDownload 14 | runServer 15 | } 16 | 17 | waitForServerDownload() { 18 | while :; do 19 | if [ -f "$enshrouded_server" ]; then 20 | break 21 | else 22 | debug "enshrouded Server is not yet downloaded - waiting" 23 | sleep 7 24 | fi 25 | done 26 | } 27 | 28 | runServer() { 29 | info "Running enshrouded-server" 30 | debug "Server config ServerName:$SERVER_NAME - ServerQueryPort:${SERVER_QUERYPORT:-15637}" 31 | 32 | export WINEDEBUG=$WINEDEBUG 33 | export STEAM_COMPAT_CLIENT_INSTALL_PATH="/home/enshrouded/.steam/steam" 34 | export STEAM_COMPAT_DATA_PATH="$install_path/steamapps/compatdata/$steam_app_id" 35 | export WINETRICKS="/usr/local/bin/winetricks" 36 | 37 | chmod +x "$enshrouded_server" 38 | proton runinprefix "$enshrouded_server" & 39 | enshrouded_server_pid=$! 40 | echo $enshrouded_server_pid >"$enshrouded_server_pidfile" 41 | 42 | wait $enshrouded_server_pid 43 | debug "enshrouded-server with PID $enshrouded_server_pid stopped" 44 | 45 | cleanup 46 | info "Shutdown complete" 47 | exit 0 48 | } 49 | 50 | cleanup() { 51 | debug "cleanup wineserver" 52 | WINEPREFIX="$install_path/steamapps/compatdata/$steam_app_id/pfx/" /usr/local/bin/files/bin/wineserver -k 53 | clearLock "$enshrouded_server_pidfile" 54 | } 55 | 56 | shutdown() { 57 | debug "Received signal to shut down enshrouded-server" 58 | if [ $enshrouded_server_pid -eq -1 ]; then 59 | debug "enshrouded server is not running yet - aborting startup" 60 | exit 61 | fi 62 | info "Shutting down enshrouded server with PID $enshrouded_server_pid" 63 | kill -TERM $enshrouded_server_pid 64 | shutdown_timeout=$(($(date +%s) + timeout)) 65 | while [ -d "/proc/$enshrouded_server_pid" ]; do 66 | if [ "$(date +%s)" -gt $shutdown_timeout ]; then 67 | shutdown_timeout=$(($(date +%s) + timeout)) 68 | warn "Timeout while waiting for server to shut down - sending SIG$kill_signal to PID $enshrouded_server_pid" 69 | kill -$kill_signal $enshrouded_server_pid 70 | case "$kill_signal" in 71 | INT) 72 | kill_signal=TERM 73 | ;; 74 | *) 75 | kill_signal=KILL 76 | ;; 77 | esac 78 | fi 79 | debug "Waiting for enshrouded Server with PID $enshrouded_server_pid to shut down" 80 | sleep 6 81 | done 82 | } 83 | 84 | trap shutdown SIGINT SIGTERM 85 | main 86 | -------------------------------------------------------------------------------- /scripts/proton/enshrouded-updater: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | . "$(dirname "$0")/common" 3 | . "$(dirname "$0")/defaults" 4 | . "$(dirname "$0")/enshrouded-updater-shared" 5 | 6 | main() { 7 | info "Running enshrouded-updater" 8 | update 9 | info "enshrouded-updater complete" 10 | } 11 | 12 | downloadEnshrouded() { 13 | debug "Downloading Enshrouded server" 14 | 15 | mkdir -p "$install_path/steamapps/compatdata/$steam_app_id" 16 | export WINETRICKS="/usr/local/bin/winetricks" 17 | export STEAM_COMPAT_CLIENT_INSTALL_PATH="/home/enshrouded/.steam/steam" 18 | export STEAM_COMPAT_DATA_PATH="$install_path/steamapps/compatdata/$steam_app_id" 19 | export STEAM_DIR="/home/enshrouded/.steam/steam/" 20 | 21 | $steamcmd_path +@sSteamCmdForcePlatformType windows +force_install_dir "$install_path" +login anonymous +app_update $steam_app_id "$GAME_BRANCH $STEAMCMD_ARGS" +quit 22 | } 23 | 24 | checkForUpdates() { 25 | local current_version 26 | 27 | if checkProtonFilesAvailable; then 28 | return 0 29 | fi 30 | 31 | if [ -f "$version_file_path" ]; then 32 | current_version=$(cat "$version_file_path") 33 | else 34 | current_version="0" 35 | fi 36 | 37 | latest_version=$(curl -sX GET "https://api.steamcmd.net/v1/info/$steam_app_id" | jq -r ".data.\"$steam_app_id\".depots.branches.$GAME_BRANCH.buildid") 38 | 39 | if [ "$latest_version" == "null" ] || [ "$latest_version" == "-1" ]; then 40 | if [ "$current_version" == "0" ]; then 41 | warn "Unable to determine latest version of enshrouded server! No version currently installed, update server anyways" 42 | return 0 43 | fi 44 | warn "Unable to determine latest version of enshrouded server! No update will be performed" 45 | return 1 46 | fi 47 | 48 | if [ "$current_version" != "$latest_version" ]; then 49 | info "Enshrouded server needs to be updated" 50 | return 0 51 | else 52 | info "Enshrouded server is already the latest version" 53 | return 1 54 | fi 55 | } 56 | 57 | checkProtonFilesAvailable() { 58 | if [ ! -d "$install_path/steamapps/compatdata/$steam_app_id" ]; then 59 | warn "Proton files are not available! Performing Enshrouded update to generate proton files" 60 | return 0 61 | fi 62 | return 1 63 | } 64 | 65 | main 66 | -------------------------------------------------------------------------------- /scripts/wine/enshrouded-bootstrap: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | . "$(dirname "$0")/common" 3 | . "$(dirname "$0")/defaults" 4 | . "$(dirname "$0")/enshrouded-bootstrap-shared" 5 | 6 | main() { 7 | info "Running enshrouded-bootstrap" 8 | prepareEnshroudedAppFolders 9 | updateOrCreateEnshroudedServerConfig 10 | prepareSteamA2sPythonLibrary 11 | 12 | bootstrapWine 13 | 14 | initCrontab 15 | bootstrapHook 16 | supervisorctl start enshrouded-updater 17 | info "Bootstrap complete" 18 | } 19 | 20 | bootstrapWine() { 21 | info "bootstrap wine" 22 | export WINEPREFIX=$WINEPREFIX 23 | export WINEARCH=$WINEARCH 24 | export WINEPATH=$WINEPATH 25 | export WINEDEBUG=$WINEDEBUG 26 | 27 | debug "winecfg" 28 | winecfg -v win10 >/dev/null 2>&1 29 | debug "wineboot" 30 | wineboot --init >/dev/null 2>&1 31 | 32 | info "wine version: $(wine --version)" 33 | 34 | info "wine bootstrap finished" 35 | } 36 | 37 | main 38 | -------------------------------------------------------------------------------- /scripts/wine/enshrouded-server: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | . "$(dirname "$0")/common" 3 | . "$(dirname "$0")/defaults" 4 | 5 | enshrouded_server_pid=-1 6 | timeout=60 7 | kill_signal=TERM 8 | 9 | cd "$install_path" || fatal "Could not cd $install_path" 10 | enshrouded_server="$install_path/$enshrouded_binary_path" 11 | 12 | main() { 13 | waitForServerDownload 14 | runServer 15 | } 16 | 17 | waitForServerDownload() { 18 | while :; do 19 | if [ -f "$enshrouded_server" ]; then 20 | break 21 | else 22 | debug "enshrouded Server is not yet downloaded - waiting" 23 | sleep 7 24 | fi 25 | done 26 | } 27 | 28 | runServer() { 29 | info "Running enshrouded-server" 30 | debug "Server config ServerName:$SERVER_NAME - ServerQueryPort:${SERVER_QUERYPORT:-15637}" 31 | 32 | export WINEPREFIX=$WINEPREFIX 33 | export WINEARCH=$WINEARCH 34 | export WINEPATH=$WINEPATH 35 | export WINEDEBUG=$WINEDEBUG 36 | 37 | chmod +x "$enshrouded_server" 38 | wine "$enshrouded_server" & 39 | enshrouded_server_pid=$! 40 | echo $enshrouded_server_pid >"$enshrouded_server_pidfile" 41 | 42 | wait $enshrouded_server_pid 43 | debug "enshrouded-server with PID $enshrouded_server_pid stopped" 44 | 45 | cleanup 46 | info "Shutdown complete" 47 | exit 0 48 | } 49 | 50 | cleanup() { 51 | clearLock "$enshrouded_server_pidfile" 52 | } 53 | 54 | shutdown() { 55 | debug "Received signal to shut down enshrouded-server" 56 | if [ $enshrouded_server_pid -eq -1 ]; then 57 | debug "enshrouded server is not running yet - aborting startup" 58 | exit 59 | fi 60 | info "Shutting down enshrouded server with PID $enshrouded_server_pid" 61 | kill -TERM $enshrouded_server_pid 62 | shutdown_timeout=$(($(date +%s) + timeout)) 63 | while [ -d "/proc/$enshrouded_server_pid" ]; do 64 | if [ "$(date +%s)" -gt $shutdown_timeout ]; then 65 | shutdown_timeout=$(($(date +%s) + timeout)) 66 | warn "Timeout while waiting for server to shut down - sending SIG$kill_signal to PID $enshrouded_server_pid" 67 | kill -$kill_signal $enshrouded_server_pid 68 | case "$kill_signal" in 69 | INT) 70 | kill_signal=TERM 71 | ;; 72 | *) 73 | kill_signal=KILL 74 | ;; 75 | esac 76 | fi 77 | debug "Waiting for enshrouded Server with PID $enshrouded_server_pid to shut down" 78 | sleep 6 79 | done 80 | } 81 | 82 | trap shutdown SIGINT SIGTERM 83 | main 84 | -------------------------------------------------------------------------------- /scripts/wine/enshrouded-updater: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | . "$(dirname "$0")/common" 3 | . "$(dirname "$0")/defaults" 4 | . "$(dirname "$0")/enshrouded-updater-shared" 5 | 6 | main() { 7 | info "Running enshrouded-updater" 8 | update 9 | info "enshrouded-updater complete" 10 | } 11 | 12 | downloadEnshrouded() { 13 | debug "Downloading Enshrouded server" 14 | $steamcmd_path +@sSteamCmdForcePlatformType windows +force_install_dir "$install_path" +login anonymous +app_update $steam_app_id "$GAME_BRANCH $STEAMCMD_ARGS" +quit 15 | } 16 | 17 | checkForUpdates() { 18 | local current_version 19 | if [ -f "$version_file_path" ]; then 20 | current_version=$(cat "$version_file_path") 21 | else 22 | current_version="0" 23 | fi 24 | 25 | latest_version=$(curl -sX GET "https://api.steamcmd.net/v1/info/$steam_app_id" | jq -r ".data.\"$steam_app_id\".depots.branches.$GAME_BRANCH.buildid") 26 | 27 | if [ "$latest_version" == "null" ] || [ "$latest_version" == "-1" ]; then 28 | if [ "$current_version" == "0" ]; then 29 | warn "Unable to determine latest version of enshrouded server! No version currently installed, update server anyways" 30 | return 0 31 | fi 32 | warn "Unable to determine latest version of enshrouded server! No update will be performed" 33 | return 1 34 | fi 35 | 36 | if [ "$current_version" != "$latest_version" ]; then 37 | info "Enshrouded server needs to be updated" 38 | return 0 39 | else 40 | info "Enshrouded server is already the latest version" 41 | return 1 42 | fi 43 | } 44 | 45 | main 46 | -------------------------------------------------------------------------------- /supervisord.conf: -------------------------------------------------------------------------------- 1 | [supervisord] 2 | user=root 3 | nodaemon=true 4 | pidfile=/var/run/supervisord.pid 5 | logfile=/var/log/supervisor/supervisord.log 6 | childlogdir=/var/log/supervisor 7 | 8 | [unix_http_server] 9 | file=/dev/shm/supervisor.sock 10 | chmod=0755 11 | chown=enshrouded:enshrouded 12 | username=dummy 13 | password=dummy 14 | 15 | [supervisorctl] 16 | serverurl=unix:///dev/shm/supervisor.sock 17 | username=dummy 18 | password=dummy 19 | 20 | [rpcinterface:supervisor] 21 | supervisor.rpcinterface_factory=supervisor.rpcinterface:make_main_rpcinterface 22 | 23 | [program:crond] 24 | user=root 25 | environment=HOME="/root",USER="root",LANG="en_US.UTF-8",PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" 26 | command=/usr/sbin/cron -f 27 | stdout_syslog=true 28 | stderr_syslog=true 29 | stdout_logfile_maxbytes=1MB 30 | stderr_logfile_maxbytes=1MB 31 | autostart=true 32 | autorestart=true 33 | priority=20 34 | 35 | [program:enshrouded-bootstrap] 36 | user=enshrouded 37 | environment=HOME="/home/enshrouded",USER="enshrouded",LANG="en_US.UTF-8",PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" 38 | command=/usr/local/etc/enshrouded/enshrouded-bootstrap 39 | directory=/home/enshrouded 40 | stdout_syslog=true 41 | stderr_syslog=true 42 | stdout_logfile_maxbytes=1MB 43 | stderr_logfile_maxbytes=1MB 44 | autostart=true 45 | autorestart=false 46 | startsecs=0 47 | startretries=0 48 | priority=30 49 | 50 | [program:enshrouded-server] 51 | user=enshrouded 52 | environment=HOME="/home/enshrouded",USER="enshrouded",LANG="en_US.UTF-8",PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" 53 | command=/usr/local/etc/enshrouded/enshrouded-server 54 | stdout_syslog=true 55 | stderr_syslog=true 56 | stdout_logfile_maxbytes=1MB 57 | stderr_logfile_maxbytes=1MB 58 | autostart=false 59 | autorestart=true 60 | startsecs=10 61 | startretries=10 62 | stopwaitsecs=90 63 | priority=100 64 | 65 | [program:enshrouded-updater] 66 | user=enshrouded 67 | environment=HOME="/home/enshrouded",USER="enshrouded",LANG="en_US.UTF-8",PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" 68 | command=/usr/local/etc/enshrouded/enshrouded-updater 69 | stdout_syslog=true 70 | stderr_syslog=true 71 | stdout_logfile_maxbytes=1MB 72 | stderr_logfile_maxbytes=1MB 73 | autostart=false 74 | autorestart=false 75 | startsecs=0 76 | 77 | [program:enshrouded-backup] 78 | user=enshrouded 79 | environment=HOME="/home/enshrouded",USER="enshrouded",LANG="en_US.UTF-8",PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" 80 | command=/usr/local/etc/enshrouded/enshrouded-backup 81 | stdout_syslog=true 82 | stderr_syslog=true 83 | stdout_logfile_maxbytes=1MB 84 | stderr_logfile_maxbytes=1MB 85 | autostart=false 86 | autorestart=false 87 | startsecs=0 88 | 89 | [program:enshrouded-force-update] 90 | user=enshrouded 91 | environment=HOME="/home/enshrouded",USER="enshrouded",LANG="en_US.UTF-8",PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" 92 | command=/usr/local/etc/enshrouded/enshrouded-force-update 93 | stdout_syslog=true 94 | stderr_syslog=true 95 | stdout_logfile_maxbytes=1MB 96 | stderr_logfile_maxbytes=1MB 97 | autostart=false 98 | autorestart=false 99 | startsecs=0 100 | 101 | [program:enshrouded-reset-roles] 102 | user=root 103 | environment=HOME="/home/enshrouded",USER="enshrouded",LANG="en_US.UTF-8",PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" 104 | command=/usr/local/etc/enshrouded/enshrouded-reset-roles 105 | stdout_syslog=true 106 | stderr_syslog=true 107 | stdout_logfile_maxbytes=1MB 108 | stderr_logfile_maxbytes=1MB 109 | autostart=false 110 | autorestart=false 111 | startsecs=0 112 | 113 | [include] 114 | files = /usr/local/etc/supervisor/conf.d/*.conf 115 | --------------------------------------------------------------------------------