tes
This commit is contained in:
27
.env
Normal file
27
.env
Normal file
@@ -0,0 +1,27 @@
|
||||
# Copy this file to .env and fill in your values
|
||||
# Discord bot token and channel
|
||||
DISCORD_TOKEN=MTA3MTEwMzcwMDAyMzY0ODMyMA.GIlFkn.o10LKcpjlaLDvVsgF_WKZhz5ykPYf1KEds_g3I
|
||||
DISCORD_CHANNEL_ID=1247178901004877916
|
||||
# Optional if using webhooks
|
||||
WEBHOOK_URL=
|
||||
|
||||
# Display name and avatar for server-origin messages when using webhooks
|
||||
SERVER_NAME=TFMC
|
||||
# Optional image URL to use as the avatar for server messages
|
||||
# SERVER_IMAGE=https://example.com/server-icon.png
|
||||
|
||||
# If logs are mounted, keep true; set to false to use remote webhook mode
|
||||
IS_LOCAL_FILE=true
|
||||
|
||||
# Path on host to the Minecraft server logs directory containing latest.log
|
||||
MC_LOGS_DIR=./data/logs
|
||||
|
||||
# Optionally override the log path inside the container
|
||||
# LOCAL_FILE_PATH_OVERRIDE=/minecraft/logs/latest.log
|
||||
|
||||
# RCON connection to send Discord -> Minecraft messages
|
||||
# Ensure server.properties has enable-rcon=true and set password/port
|
||||
# Set IP to the Minecraft server host or container name on the Docker network
|
||||
MINECRAFT_SERVER_RCON_IP=mc
|
||||
MINECRAFT_SERVER_RCON_PORT=25575
|
||||
MINECRAFT_SERVER_RCON_PASSWORD=509dbd71b996df2bd575d43b
|
||||
27
.env.example
Normal file
27
.env.example
Normal file
@@ -0,0 +1,27 @@
|
||||
# Copy this file to .env and fill in your values
|
||||
# Discord bot token and channel
|
||||
DISCORD_TOKEN=
|
||||
DISCORD_CHANNEL_ID=
|
||||
# Optional if using webhooks
|
||||
WEBHOOK_URL=
|
||||
|
||||
# Display name and avatar for server-origin messages when using webhooks
|
||||
SERVER_NAME=Shulker
|
||||
# Optional image URL to use as the avatar for server messages
|
||||
# SERVER_IMAGE=https://example.com/server-icon.png
|
||||
|
||||
# If logs are mounted, keep true; set to false to use remote webhook mode
|
||||
IS_LOCAL_FILE=true
|
||||
|
||||
# Path on host to the Minecraft server logs directory containing latest.log
|
||||
MC_LOGS_DIR=./data/logs
|
||||
|
||||
# Optionally override the log path inside the container
|
||||
# LOCAL_FILE_PATH_OVERRIDE=/minecraft/logs/latest.log
|
||||
|
||||
# RCON connection to send Discord -> Minecraft messages
|
||||
# Ensure server.properties has enable-rcon=true and set password/port
|
||||
# Set IP to the Minecraft server host or container name on the Docker network
|
||||
MINECRAFT_SERVER_RCON_IP=127.0.0.1
|
||||
MINECRAFT_SERVER_RCON_PORT=25575
|
||||
MINECRAFT_SERVER_RCON_PASSWORD=
|
||||
52
README.md
52
README.md
@@ -21,3 +21,55 @@ Website for TFMC (teknisk fysiks minecraft server)
|
||||
- Maybe use integration with itgz, and get variables from those servers? via for example docker sock? or would that be to insecure?
|
||||
[] Maybe integrate chat with discord via rcon?
|
||||
- Base on existing project? This one exist and could maybe be useful? https://github.com/destruc7i0n/shulker
|
||||
|
||||
## Shulker Discord-Minecraft Bridge (Dockerized)
|
||||
|
||||
This repo includes [Shulker](https://github.com/destruc7i0n/shulker) as a Git submodule under `external/shulker`, plus a Docker setup so you can run it and mount your Minecraft logs as a volume.
|
||||
|
||||
### Prereqs
|
||||
- Docker and Docker Compose installed
|
||||
- A Discord bot token and (optionally) a Discord channel webhook
|
||||
- Your Minecraft server configured with rcon and accessible logs
|
||||
|
||||
### First-time setup
|
||||
1. Initialize and update submodules:
|
||||
- git submodule update --init --recursive
|
||||
2. Configure environment variables (create a `.env` in repo root or pass via CLI):
|
||||
- DISCORD_TOKEN=... (required)
|
||||
- DISCORD_CHANNEL_ID=... (required if not using webhooks only)
|
||||
- WEBHOOK_URL=... (if using webhooks)
|
||||
- MC_LOGS_DIR=/absolute/path/to/your/minecraft/logs (defaults to `./Worlds/tfmc23-24/logs`)
|
||||
- IS_LOCAL_FILE=true to tail logs directly (recommended when logs are mounted)
|
||||
|
||||
### Run
|
||||
Start the service (from repo root):
|
||||
|
||||
```
|
||||
docker compose up -d --build shulker
|
||||
```
|
||||
|
||||
On first run, `/data/config.json` will be created from `config.example.json`. The container will symlink it to `/app/config.json` and set `IS_LOCAL_FILE` and `LOCAL_FILE_PATH` to `/minecraft/logs/latest.log` by default. You can edit `config.json` by entering the container or by stopping the container and editing the file in the named volume.
|
||||
|
||||
Expose the Shulker webhook on port 8000 if you want to send remote hooks instead of tailing logs. For remote setup, set `IS_LOCAL_FILE=false` and follow the command in Shulker's README to pipe log lines to the webhook.
|
||||
|
||||
### Volumes
|
||||
- `shulker_data` named volume stores `config.json`.
|
||||
- `${MC_LOGS_DIR}` (host) is mounted read-only at `/minecraft/logs` (container). Ensure this path contains `latest.log`.
|
||||
|
||||
### Updating Shulker
|
||||
Shulker is a submodule:
|
||||
|
||||
```
|
||||
git submodule update --remote external/shulker
|
||||
```
|
||||
|
||||
Rebuild the image after updating:
|
||||
|
||||
```
|
||||
docker compose build shulker && docker compose up -d shulker
|
||||
```
|
||||
|
||||
### Notes
|
||||
- Node 16+ is required; the Docker image uses Node 18 Alpine.
|
||||
- If your server is modded, you may need to adjust `REGEX_SERVER_PREFIX` per Shulker’s FAQ.
|
||||
- For RCON features, set `MINECRAFT_SERVER_RCON_*` in `config.json` and ensure your server has rcon enabled.
|
||||
|
||||
5
data/.gitignore
vendored
Normal file
5
data/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
|
||||
# But keep this file so the directory exists in the repo
|
||||
!.gitignore
|
||||
58
docker-compose.yml
Normal file
58
docker-compose.yml
Normal file
@@ -0,0 +1,58 @@
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
shulker:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/shulker/Dockerfile
|
||||
container_name: shulker
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
# Provide these via environment or .env file
|
||||
- DISCORD_TOKEN=${DISCORD_TOKEN}
|
||||
- DISCORD_CHANNEL_ID=${DISCORD_CHANNEL_ID}
|
||||
- WEBHOOK_URL=${WEBHOOK_URL}
|
||||
- SERVER_NAME=${SERVER_NAME:-Shulker}
|
||||
- SERVER_IMAGE=${SERVER_IMAGE}
|
||||
- DISCORD_MESSAGE_TEMPLATE=${DISCORD_MESSAGE_TEMPLATE}
|
||||
- DEBUG=${DEBUG}
|
||||
- ALLOW_USER_MENTIONS=${ALLOW_USER_MENTIONS}
|
||||
- ALLOW_HERE_EVERYONE_MENTIONS=${ALLOW_HERE_EVERYONE_MENTIONS}
|
||||
- MINECRAFT_SERVER_RCON_IP=${MINECRAFT_SERVER_RCON_IP}
|
||||
- MINECRAFT_SERVER_RCON_PORT=${MINECRAFT_SERVER_RCON_PORT}
|
||||
- MINECRAFT_SERVER_RCON_PASSWORD=${MINECRAFT_SERVER_RCON_PASSWORD}
|
||||
- MINECRAFT_TELLRAW_DOESNT_EXIST=${MINECRAFT_TELLRAW_DOESNT_EXIST}
|
||||
- MINECRAFT_TELLRAW_TEMPLATE=${MINECRAFT_TELLRAW_TEMPLATE}
|
||||
- MINECRAFT_TELLRAW_DOESNT_EXIST_SAY_TEMPLATE=${MINECRAFT_TELLRAW_DOESNT_EXIST_SAY_TEMPLATE}
|
||||
# Set to false if using remote hook mode
|
||||
- IS_LOCAL_FILE=${IS_LOCAL_FILE:-true}
|
||||
# Optionally override the log path inside the container
|
||||
- LOCAL_FILE_PATH_OVERRIDE=${LOCAL_FILE_PATH_OVERRIDE}
|
||||
volumes:
|
||||
# Persist config.json in a named volume
|
||||
- shulker_data:/data
|
||||
# Map your host/server Minecraft logs into the container
|
||||
- ${MC_LOGS_DIR:-./data/logs}:/minecraft/logs:ro
|
||||
ports:
|
||||
- "8000:8000"
|
||||
|
||||
mc:
|
||||
image: itzg/minecraft-server
|
||||
tty: true
|
||||
stdin_open: true
|
||||
ports:
|
||||
- "25565:25565"
|
||||
environment:
|
||||
EULA: "TRUE"
|
||||
ENABLE_RCON: "true"
|
||||
RCON_PASSWORD: ${MINECRAFT_SERVER_RCON_PASSWORD}
|
||||
RCON_PORT: ${MINECRAFT_SERVER_RCON_PORT}
|
||||
# Ensure env values are written into server.properties on each start
|
||||
OVERRIDE_SERVER_PROPERTIES: "true"
|
||||
volumes:
|
||||
# attach the relative directory 'data' to the container's /data path
|
||||
- ./data:/data
|
||||
|
||||
volumes:
|
||||
shulker_data:
|
||||
driver: local
|
||||
49
docker/shulker/Dockerfile
Normal file
49
docker/shulker/Dockerfile
Normal file
@@ -0,0 +1,49 @@
|
||||
# Build Shulker without modifying the submodule; run as non-root; persist config and read logs via volumes
|
||||
FROM node:22-alpine AS build
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Enable corepack so yarn is available (Node 18+)
|
||||
RUN corepack enable
|
||||
|
||||
# Copy only dependency manifests first for better layer caching
|
||||
COPY external/shulker/package.json external/shulker/yarn.lock ./external/shulker/
|
||||
|
||||
WORKDIR /app/external/shulker
|
||||
|
||||
# Install dependencies
|
||||
RUN yarn install --frozen-lockfile || yarn install
|
||||
|
||||
# Copy source and build
|
||||
COPY external/shulker/ /app/external/shulker/
|
||||
RUN yarn build
|
||||
|
||||
FROM node:22-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy built app from builder
|
||||
COPY --from=build /app/external/shulker /app
|
||||
|
||||
# Prepare runtime directories and non-root user
|
||||
RUN adduser -D -h /app -u 10001 shulker \
|
||||
&& mkdir -p /data /minecraft/logs \
|
||||
&& chown -R shulker:shulker /app /data /minecraft
|
||||
|
||||
# Copy entrypoint
|
||||
COPY docker/shulker/entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
# Install helpful runtime tools
|
||||
RUN apk add --no-cache jq
|
||||
|
||||
USER shulker
|
||||
|
||||
# Shulker default port
|
||||
EXPOSE 8000
|
||||
|
||||
# Volumes: /data holds config.json, /minecraft/logs maps to the server logs
|
||||
VOLUME ["/data", "/minecraft/logs"]
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
CMD ["node", "build/index.js"]
|
||||
90
docker/shulker/entrypoint.sh
Normal file
90
docker/shulker/entrypoint.sh
Normal file
@@ -0,0 +1,90 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# If no config exists in /data, seed it from the example and apply env overrides if provided
|
||||
if [ ! -f /data/config.json ]; then
|
||||
echo "Seeding /data/config.json from example"
|
||||
cp /app/config.example.json /data/config.json
|
||||
fi
|
||||
|
||||
# Ensure LOCAL_FILE_PATH points to the mounted logs unless explicitly overridden via env
|
||||
if [ -z "${LOCAL_FILE_PATH_OVERRIDE}" ]; then
|
||||
LOCAL_FILE_PATH="/minecraft/logs/latest.log"
|
||||
else
|
||||
LOCAL_FILE_PATH="${LOCAL_FILE_PATH_OVERRIDE}"
|
||||
fi
|
||||
|
||||
# Apply a few common ENV overrides into config.json if provided
|
||||
json_set() {
|
||||
KEY="$1"; VALUE="$2"; FILE="$3"
|
||||
# Use jq if available for robust edits; otherwise sed fallback
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
tmp=$(mktemp)
|
||||
jq --arg v "$VALUE" ".[$KEY]=$VALUE" "$FILE" > "$tmp" && mv "$tmp" "$FILE" || true
|
||||
else
|
||||
# naive sed replace; expects simple string or number values already present
|
||||
sed -i "s#\(\"$KEY\"\): .*#\\\"$KEY\\\": $VALUE,#" "$FILE" || true
|
||||
fi
|
||||
}
|
||||
|
||||
# Build a small jq script to apply overrides
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
jq \
|
||||
--argfile cfg /data/config.json \
|
||||
'.' >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
# When env vars are set, write them. Values must be valid JSON literals (strings quoted).
|
||||
[ -n "${DISCORD_TOKEN}" ] && jq ".DISCORD_TOKEN=\"${DISCORD_TOKEN}\"" /data/config.json > /data/config.json.tmp && mv /data/config.json.tmp /data/config.json || true
|
||||
[ -n "${DISCORD_CHANNEL_ID}" ] && jq ".DISCORD_CHANNEL_ID=\"${DISCORD_CHANNEL_ID}\"" /data/config.json > /data/config.json.tmp && mv /data/config.json.tmp /data/config.json || true
|
||||
[ -n "${WEBHOOK_URL}" ] && jq ".WEBHOOK_URL=\"${WEBHOOK_URL}\"" /data/config.json > /data/config.json.tmp && mv /data/config.json.tmp /data/config.json || true
|
||||
[ -n "${DISCORD_MESSAGE_TEMPLATE}" ] && jq ".DISCORD_MESSAGE_TEMPLATE=\"${DISCORD_MESSAGE_TEMPLATE}\"" /data/config.json > /data/config.json.tmp && mv /data/config.json.tmp /data/config.json || true
|
||||
[ -n "${DEBUG}" ] && jq ".DEBUG=${DEBUG}" /data/config.json > /data/config.json.tmp && mv /data/config.json.tmp /data/config.json || true
|
||||
|
||||
# Default behavior: if no WEBHOOK_URL, disable webhooks; otherwise enable them.
|
||||
# If USE_WEBHOOKS is explicitly set via env, it overrides this default.
|
||||
if [ -z "${USE_WEBHOOKS}" ]; then
|
||||
if jq -e '.WEBHOOK_URL and (.WEBHOOK_URL | length) > 0' /data/config.json >/dev/null 2>&1; then
|
||||
jq ".USE_WEBHOOKS=true" /data/config.json > /data/config.json.tmp && mv /data/config.json.tmp /data/config.json
|
||||
else
|
||||
jq ".USE_WEBHOOKS=false" /data/config.json > /data/config.json.tmp && mv /data/config.json.tmp /data/config.json
|
||||
fi
|
||||
else
|
||||
case "${USE_WEBHOOKS}" in
|
||||
[Tt][Rr][Uu][Ee]|1|yes|on) jq ".USE_WEBHOOKS=true" /data/config.json > /data/config.json.tmp && mv /data/config.json.tmp /data/config.json ;;
|
||||
[Ff][Aa][Ll][Ss][Ee]|0|no|off) jq ".USE_WEBHOOKS=false" /data/config.json > /data/config.json.tmp && mv /data/config.json.tmp /data/config.json ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Customize server identity shown in Discord when posting server messages via webhook
|
||||
[ -n "${SERVER_NAME}" ] && jq ".SERVER_NAME=\"${SERVER_NAME}\"" /data/config.json > /data/config.json.tmp && mv /data/config.json.tmp /data/config.json || true
|
||||
[ -n "${SERVER_IMAGE}" ] && jq ".SERVER_IMAGE=\"${SERVER_IMAGE}\"" /data/config.json > /data/config.json.tmp && mv /data/config.json.tmp /data/config.json || true
|
||||
|
||||
# RCON configuration overrides
|
||||
[ -n "${MINECRAFT_SERVER_RCON_IP}" ] && jq ".MINECRAFT_SERVER_RCON_IP=\"${MINECRAFT_SERVER_RCON_IP}\"" /data/config.json > /data/config.json.tmp && mv /data/config.json.tmp /data/config.json || true
|
||||
if [ -n "${MINECRAFT_SERVER_RCON_PORT}" ]; then
|
||||
case "${MINECRAFT_SERVER_RCON_PORT}" in
|
||||
''|*[!0-9]*) jq ".MINECRAFT_SERVER_RCON_PORT=\"${MINECRAFT_SERVER_RCON_PORT}\"" /data/config.json > /data/config.json.tmp && mv /data/config.json.tmp /data/config.json ;;
|
||||
*) jq ".MINECRAFT_SERVER_RCON_PORT=${MINECRAFT_SERVER_RCON_PORT}" /data/config.json > /data/config.json.tmp && mv /data/config.json.tmp /data/config.json ;;
|
||||
esac
|
||||
fi
|
||||
[ -n "${MINECRAFT_SERVER_RCON_PASSWORD}" ] && jq ".MINECRAFT_SERVER_RCON_PASSWORD=\"${MINECRAFT_SERVER_RCON_PASSWORD}\"" /data/config.json > /data/config.json.tmp && mv /data/config.json.tmp /data/config.json || true
|
||||
|
||||
# Minecraft output formatting overrides
|
||||
if [ -n "${MINECRAFT_TELLRAW_DOESNT_EXIST}" ]; then
|
||||
case "${MINECRAFT_TELLRAW_DOESNT_EXIST}" in
|
||||
[Tt][Rr][Uu][Ee]|1|yes|on) jq ".MINECRAFT_TELLRAW_DOESNT_EXIST=true" /data/config.json > /data/config.json.tmp && mv /data/config.json.tmp /data/config.json ;;
|
||||
[Ff][Aa][Ll][Ss][Ee]|0|no|off) jq ".MINECRAFT_TELLRAW_DOESNT_EXIST=false" /data/config.json > /data/config.json.tmp && mv /data/config.json.tmp /data/config.json ;;
|
||||
esac
|
||||
fi
|
||||
[ -n "${MINECRAFT_TELLRAW_TEMPLATE}" ] && jq ".MINECRAFT_TELLRAW_TEMPLATE=\"${MINECRAFT_TELLRAW_TEMPLATE}\"" /data/config.json > /data/config.json.tmp && mv /data/config.json.tmp /data/config.json || true
|
||||
[ -n "${MINECRAFT_TELLRAW_DOESNT_EXIST_SAY_TEMPLATE}" ] && jq ".MINECRAFT_TELLRAW_DOESNT_EXIST_SAY_TEMPLATE=\"${MINECRAFT_TELLRAW_DOESNT_EXIST_SAY_TEMPLATE}\"" /data/config.json > /data/config.json.tmp && mv /data/config.json.tmp /data/config.json || true
|
||||
|
||||
# Always set IS_LOCAL_FILE true and path to mounted logs unless overridden explicitly via env IS_LOCAL_FILE
|
||||
if [ -z "${IS_LOCAL_FILE}" ]; then IS_LOCAL_FILE=true; fi
|
||||
jq ".IS_LOCAL_FILE=${IS_LOCAL_FILE} | .LOCAL_FILE_PATH=\"${LOCAL_FILE_PATH}\"" /data/config.json > /data/config.json.tmp && mv /data/config.json.tmp /data/config.json
|
||||
|
||||
# Link config into app directory where shulker expects it
|
||||
ln -sf /data/config.json /app/config.json
|
||||
|
||||
exec "$@"
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"id" : "edc64ca33ed24de1852b11051edc82e5",
|
||||
"name" : "Millerman03"
|
||||
}
|
||||
0
requirements.txt
Normal file
0
requirements.txt
Normal file
Reference in New Issue
Block a user