- Python 78.2%
- HTML 21.8%
chunky cancel doesn't delete the task file, it just writes cancelled=true into it - the paused/finished check only tested file existence, so a cancelled pregen looked identical to a paused one forever, spamming the same presence update every tick with no way to resolve. Now reads the cancelled flag and treats it like a finished task. Bump to 1.16.1. |
||
|---|---|---|
| .gitignore | ||
| admin_page.html | ||
| bot.py | ||
| chunky_toggle.py | ||
| config.ini.example | ||
| mods_page.html | ||
| README.md | ||
| status_page.html | ||
Yor — MTR France Discord ↔ Minecraft bridge bot
A discord.py bot bridging a Discord channel with the MTR France Minecraft server over RCON and Docker log tailing. Named after Yor Forger (Spy x Family), matching this project's anime-character naming convention for tooling (see also "Levi", the modpack sync mod, in this same org).
What it does
- Chat relay, both directions. Messages sent in the configured Discord
channel are pushed into the server via RCON
tellraw; server chat, joins, leaves, advancements, and deaths are tailed fromdocker logs -fand posted as Discord messages/embeds. - Container status tracking. Polls
docker inspectevery 30s; announces the container stopping/restarting, and reports if RCON becomes unreachable (once per outage, not repeatedly). - Presence, topic, and MOTD, kept in sync with player count / uptime, or — while a Chunky pregen is active — with pregen progress instead.
- Chunky pregen tracking with a smoothed ETA. Chunky's own
chunky progressRCON output includes an ETA, but it's recomputed from a short-term instantaneous rate every time it's queried, so it swings wildly (chunk generation speed varies a lot with terrain/structures). Yor keeps its own rolling window of(timestamp, percent)samples and derives a much steadier completion estimate from the slope across that whole window instead — seesmoothed_eta_epoch()inbot.py. That estimate is shown as a live, auto-localizing Discord timestamp (<t:...:f> (<t:...:R>)) in actual channel messages, and as a plain "Xh Ymin" duration in contexts that don't render Discord markup (bot presence, server MOTD, channel topic). - Auto-triggers a Distant Horizons LOD pregen once Chunky's own pregen crosses 95%, and announces genuine completion (distinguishing "paused" from "finished" by checking Chunky's on-disk task file, so a multi-minute pause during testing doesn't get misread as completion).
!pregen/!chunky/!progress— on-demand progress check.!help/!aide— usage reminder.
Configuration
Real secrets (config.ini) are not committed — see config.ini.example
for the expected shape:
[bot]
token = YOUR_DISCORD_BOT_TOKEN
channel_id = YOUR_DISCORD_CHANNEL_ID
[minecraft]
container_name = YOUR_PTERODACTYL_CONTAINER_ID
rcon_host = 172.18.0.2
rcon_port = 25575
rcon_password = YOUR_RCON_PASSWORD
Copy it to config.ini and fill in real values before running. rcon_host is
the Docker-internal IP of the game server container (Pterodactyl's own network,
not localhost — the bot and the game container are separate Docker
containers/processes).
chunky_toggle.py (a standalone helper for pausing/resuming Chunky manually,
independent of the bot process) reads the same config.ini — it used to have
the RCON password hardcoded directly in source, which has been fixed to read
from config instead.
Running
Requires Python 3 with discord.py and psutil (pip install discord.py psutil
inside a venv is what production actually uses — see the systemd unit below).
aiohttp (used for the status page's tiny HTTP server) comes in as a
dependency of discord.py already.
python3 -m venv venv
./venv/bin/pip install discord.py psutil
./venv/bin/python3 bot.py
Production deployment (systemd)
MTR France runs this as a systemd service, mc-discord-bot.service:
[Unit]
Description=Minecraft <-> Discord chat bridge bot
After=network-online.target docker.service
Wants=network-online.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/mc-discord-bot
Environment=PYTHONUNBUFFERED=1
ExecStart=/opt/mc-discord-bot/venv/bin/python3 -u /opt/mc-discord-bot/bot.py
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Deployed at /opt/mc-discord-bot/ on the same VPS as the Pterodactyl panel
(so docker/RCON access to the game container is local). After changing
bot.py:
sudo cp bot.py /opt/mc-discord-bot/bot.py
sudo systemctl restart mc-discord-bot
sudo systemctl status mc-discord-bot --no-pager
Known constraints / things to know before touching this
- The bot needs
dockerCLI access (it shells out todocker inspect/docker logs) and network-level RCON access to the game container — it currently runs asrootspecifically for unrestricteddockeraccess; tightening this (e.g. a docker group membership instead of root) hasn't been done. - Discord hard-limits channel topic edits to roughly 2 per 10 minutes per
channel — the pregen loop deliberately throttles topic updates to once per
15 minutes (
topic_counter >= 15, one tick per minute) to stay well under that, and the hourly detailed channel message is pinned to a fixed wall-clock minute (:18) rather than a tick counter, so it doesn't drift or double-fire after a bot restart. - The smoothed ETA needs at least 5 minutes of accumulated history
(
MIN_HISTORY_SPAN_SECONDS) before it will show a real estimate — shows "calcul en cours..." until then, including right after every bot restart (the rolling history is in-memory only, not persisted).