Skip to content

Commit e62c526

Browse files
authored
Merge pull request #84 from adamhl8/mod-support
add mod support
2 parents 3d915e4 + b0c7021 commit e62c526

6 files changed

Lines changed: 188 additions & 7 deletions

File tree

Dockerfile

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ ENV STEAMAPP=core-keeper
1515
ENV STEAMAPPDIR="${HOMEDIR}/${STEAMAPP}-dedicated"
1616
ENV STEAMAPPDATADIR="${HOMEDIR}/${STEAMAPP}-data"
1717
ENV SCRIPTSDIR="${HOMEDIR}/scripts"
18-
ENV MODSDIR="${STEAMAPPDATADIR}/StreamingAssets/Mods"
18+
ENV MODSDIR="${STEAMAPPDIR}/CoreKeeperServer_Data/StreamingAssets/Mods"
1919
ENV DLURL=https://raw.githubusercontent.com/escapingnetwork/core-keeper-dedicated
2020

2121
ARG TARGETARCH
@@ -33,6 +33,7 @@ RUN set -x \
3333
tzdata \
3434
gosu \
3535
jo \
36+
jq \
3637
gettext-base \
3738
unzip \
3839
wget \
@@ -126,7 +127,12 @@ ENV PUID=1000 \
126127
DISCORD_SERVER_STOP_ENABLED=true \
127128
DISCORD_SERVER_STOP_MESSAGE="" \
128129
DISCORD_SERVER_STOP_TITLE="Server Stopped" \
129-
DISCORD_SERVER_STOP_COLOR="12779520"
130+
DISCORD_SERVER_STOP_COLOR="12779520" \
131+
# Mods
132+
MODS_ENABLED=false \
133+
MODIO_API_KEY="" \
134+
MODIO_API_URL="" \
135+
MODS=""
130136

131137
# Switch to workdir
132138
WORKDIR ${HOMEDIR}

README.md

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ volumes:
5959
server-data:
6060
```
6161
62-
Create a `override.env` file and override the desired enviromental variables for the dedicated server, see configuration for reference. Example:
62+
Create a `override.env` file and override the desired environmental variables for the dedicated server, see configuration for reference. Example:
6363
```env
6464
ARM64_DEVICE=rpi5
6565
MAX_PLAYERS=3
@@ -81,7 +81,7 @@ These are the arguments you can use to customize server behavior with default va
8181
| PUID | 1000 | The user ID on the host that the container should use for file ownership and permissions. |
8282
| PGID | 1000 | The group ID on the host that the container should use for file ownership and permissions. |
8383
| ARM64_DEVICE | generic | The Box64 build variants. Accepts `generic`, `rpi5`, `m1` and `adlink`. |
84-
| USE_DEPOT_DOWNLOADER | false | Use Depot downloader instead of steamcmd. Useful for system not compatible with 32 bits. |
84+
| USE_DEPOT_DOWNLOADER | false | Use Depot downloader instead of steamcmd. Useful for system not compatible with 32 bits. |
8585
| WORLD_INDEX | 0 | Which world index to use. |
8686
| WORLD_NAME | "Core Keeper Server" | The name to use for the server. |
8787
| WORLD_SEED | "" | The seed to use for a new world. Set to "" to generate random seed. |
@@ -109,8 +109,51 @@ These are the arguments you can use to customize server behavior with default va
109109
| DISCORD_SERVER_STOP_MESSAGE | "" | Embed message |
110110
| DISCORD_SERVER_STOP_TITLE | "Server Stopped" | Embed title |
111111
| DISCORD_SERVER_STOP_COLOR | "12779520" | Embed color |
112+
| MODS_ENABLED | false | Enable/Disable mod support |
113+
| MODIO_API_KEY | "" | mod.io API key |
114+
| MODIO_API_URL | "" | mod.io API path |
115+
| MODS | "" | List of mods to install |
116+
117+
## Mod Support
118+
119+
The container supports automatically installing mods from [mod.io](https://mod.io/g/corekeeper).
120+
121+
1. Get a mod.io API key from [mod.io/me/access](https://mod.io/me/access)
122+
- You'll need the API path that is generated along with the key (e.g. https://u-*.modapi.io/v1)
123+
2. Set the necessary environment variables in your `override.env` file (or in your `docker-compose.yml`)
124+
- `MODS_ENABLED=true`
125+
- `MODIO_API_KEY=your_api_key`
126+
- `MODIO_API_URL=your_api_url`
127+
- `MODS=mod1,mod2` (see below)
128+
129+
### Specify mods to install
130+
131+
> [!WARNING]
132+
> Installing a client-only mod can cause the server to not start. Don't install client-only mods (they wouldn't do anything on the server anyway).
133+
134+
> [!IMPORTANT]
135+
> Mod dependencies are not automatically installed. You must look at the dependencies for each mod you want to install and add their dependencies to the list.
136+
137+
You'll need to get the mod string ID from mod.io for each mod you want to install. The easiest way to do this is to grab it from the URL.
138+
139+
For example, looking at the URL for [CoreLib](https://mod.io/g/corekeeper/m/core-lib) (`https://mod.io/g/corekeeper/m/core-lib`), you would use `core-lib`.
140+
141+
Specify mods as a comma-separated list, optionally providing a version:
142+
143+
```sh
144+
# Format: <mod_id>[:<version>], ...
145+
MODS=core-lib,coreliblocalization,corelibrewiredextension,ck-qol
146+
```
147+
148+
Example using specific versions:
149+
150+
```sh
151+
MODS=core-lib,coreliblocalization,corelibrewiredextension:3.0.1,ck-qol:1.9.4
152+
```
153+
154+
- If `version` is not specified, the latest version will be installed.
155+
- Mods are reinstalled whenever the container is started, so to update mods to their latest version, simply restart the container.
112156

113-
114157
### Contributors
115158
<a href="https://github.com/escapingnetwork/core-keeper-dedicated/graphs/contributors">
116159
<img src="https://contrib.rocks/image?repo=escapingnetwork/core-keeper-dedicated" />

docker-compose-example/.env

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,8 @@ DISCORD_SERVER_STOP_ENABLED=true
3333
DISCORD_SERVER_STOP_MESSAGE=""
3434
DISCORD_SERVER_STOP_TITLE="Server Stopped"
3535
DISCORD_SERVER_STOP_COLOR="12779520"
36+
# Mods
37+
MODS_ENABLED=false
38+
MODIO_API_KEY=""
39+
MODIO_API_URL=""
40+
MODS=""

docker-compose-example/docker-compose.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ services:
1313
restart: unless-stopped
1414
stop_grace_period: 2m
1515
volumes:
16-
server-files:
17-
server-data:
16+
server-files:
17+
server-data:

scripts/mod-manager.sh

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
#!/bin/bash
2+
source "${SCRIPTSDIR}/helper-functions.sh"
3+
4+
MODIO_CORE_KEEPER_ENDPOINT="${MODIO_API_URL}/games/@corekeeper/mods"
5+
6+
download_and_install_mod() {
7+
if [ -z "${MODIO_API_KEY}" ]; then
8+
LogError "MODIO_API_KEY is required for downloading mods"
9+
exit 1
10+
fi
11+
12+
local mod_string_id="$1"
13+
local version="$2"
14+
15+
# The mod.io API needs the mod string id to be prefixed with @
16+
local modio_mod_endpoint="${MODIO_CORE_KEEPER_ENDPOINT}/@${mod_string_id}"
17+
local download_url
18+
local actual_version
19+
20+
local mod_info
21+
mod_info=$(curl -s "${modio_mod_endpoint}?api_key=${MODIO_API_KEY}")
22+
23+
if [ -z "$mod_info" ]; then
24+
LogError "Failed to get mod info for mod ${mod_string_id}"
25+
exit 1
26+
fi
27+
28+
local mod_name
29+
mod_name=$(echo "$mod_info" | jq -r ".name")
30+
31+
if [ -n "$version" ]; then
32+
# Get all files for the mod
33+
local mod_files
34+
mod_files=$(curl -s "${modio_mod_endpoint}/files?api_key=${MODIO_API_KEY}")
35+
36+
if [ -z "$mod_files" ]; then
37+
LogError "Failed to get mod files for ${mod_name} (${mod_string_id})"
38+
exit 1
39+
fi
40+
41+
# Find the specified version
42+
download_url=$(echo "$mod_files" | jq -r ".data[] | select(.version == \"${version}\") | .download.binary_url")
43+
if [ -z "$download_url" ] || [ "$download_url" = "null" ]; then
44+
LogError "Version ${version} not found for mod ${mod_name} (${mod_string_id})"
45+
exit 1
46+
fi
47+
actual_version="$version"
48+
else
49+
# Use latest version
50+
download_url=$(echo "$mod_info" | jq -r ".modfile.download.binary_url")
51+
actual_version=$(echo "$mod_info" | jq -r ".modfile.version")
52+
fi
53+
54+
if [ -z "$download_url" ] || [ "$download_url" = "null" ]; then
55+
LogError "Failed to get download URL for mod ${mod_name} (${mod_string_id})"
56+
exit 1
57+
fi
58+
59+
# Create temp directory for download
60+
local temp_dir
61+
temp_dir=$(mktemp -d)
62+
local temp_mod_download="${temp_dir}/${mod_string_id}.zip"
63+
64+
local mod_dir="${MODSDIR}/${mod_string_id}"
65+
66+
# Download and extract mod
67+
if curl -s -L "${download_url}?api_key=${MODIO_API_KEY}" -o "${temp_mod_download}"; then
68+
# Create mod directory and extract
69+
mkdir -p "${mod_dir}"
70+
unzip -q "${temp_mod_download}" -d "${mod_dir}"
71+
LogInfo "Installed ${mod_name} (${mod_string_id}) ${actual_version}"
72+
else
73+
LogError "Failed to install ${mod_name} (${mod_string_id}) ${actual_version}"
74+
exit 1
75+
fi
76+
77+
# Cleanup
78+
rm -rf "${temp_dir}"
79+
}
80+
81+
install_mods() {
82+
# Split the comma-separated list of mods
83+
IFS=',' read -ra mod_list <<< "$MODS"
84+
85+
for mod_spec in "${mod_list[@]}"; do
86+
# Trim whitespace
87+
mod_spec=$(echo "$mod_spec" | tr -d '[:space:]')
88+
[ -z "$mod_spec" ] && continue
89+
90+
local mod_string_id
91+
local version
92+
# Split into id and version
93+
if [[ "$mod_spec" =~ ":" ]]; then
94+
mod_string_id="${mod_spec%%:*}" # Everything before the colon
95+
version="${mod_spec#*:}" # Everything after the colon
96+
else
97+
mod_string_id="$mod_spec"
98+
version=""
99+
fi
100+
101+
download_and_install_mod "$mod_string_id" "$version"
102+
done
103+
}
104+
105+
manage_mods() {
106+
# We always clear the mods directory so the installed mods reflect exactly what was specified by the user
107+
rm -rf "${MODSDIR}"
108+
mkdir -p "${MODSDIR}"
109+
110+
if [[ "${MODS_ENABLED,,}" != "true" ]]; then
111+
LogInfo "MODS_ENABLED is not true, skipping mod installation"
112+
return 0
113+
fi
114+
115+
if [ -z "${MODS}" ]; then
116+
LogWarn "MODS_ENABLED is true but there are no mods specified"
117+
return 0
118+
fi
119+
120+
LogInfo "Installing mods..."
121+
install_mods
122+
}

scripts/setup.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
#!/bin/bash
2+
3+
source "${SCRIPTSDIR}/mod-manager.sh"
4+
25
mkdir -p "${STEAMAPPDIR}" || true
36

47
# Initialize arguments array
@@ -29,4 +32,6 @@ else
2932
"$STEAMCMDDIR/steamcmd.sh" "${args[@]}"
3033
fi
3134

35+
manage_mods
36+
3237
exec bash "${SCRIPTSDIR}/launch.sh"

0 commit comments

Comments
 (0)