init
This commit is contained in:
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Auto detect text files and perform LF normalization
|
||||||
|
* text=auto
|
||||||
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
data/*
|
||||||
|
backups/*.tar.gz
|
||||||
17
README.md
Normal file
17
README.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
**Struktura**
|
||||||
|
|
||||||
|
mc-server/
|
||||||
|
├── data/ # Svět a soubory serveru (svázané přes Docker volume)
|
||||||
|
├── backups/ # Automatické zálohy
|
||||||
|
├── docker-compose.yml # Minecraft server v Dockeru
|
||||||
|
├── backup.sh # 🔁 Pravidelné zálohy světa
|
||||||
|
├── restore.sh # ♻️ Obnova zálohy podle výběru
|
||||||
|
├── start.sh # ▶️ Spuštění serveru
|
||||||
|
├── stop.sh # ⛔ Zastavení serveru (volitelné)
|
||||||
|
└── restart.sh # 🔄 Restart serveru (volitelné)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**cron job:**
|
||||||
|
|
||||||
|
*/15 * * * * /cesta/mc-server/backup.sh >> /cesta/mc-server/backup.log 2>&1
|
||||||
39
backup.sh
Normal file
39
backup.sh
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Absolutní cesta ke skriptu
|
||||||
|
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
|
CONTAINER="mc-vanilla"
|
||||||
|
BACKUP_DIR="/mnt/backups/minecraft_backups/frankstein"
|
||||||
|
WORLD_DIR="$DIR/data/world"
|
||||||
|
|
||||||
|
DATE_FULL=$(date +%F_%H-%M)
|
||||||
|
DATE_HOUR=$(date +%F_%H)
|
||||||
|
DATE_DAY=$(date +%F)
|
||||||
|
|
||||||
|
ARCHIVE_NAME="$BACKUP_DIR/world_$DATE_FULL.tar.gz"
|
||||||
|
|
||||||
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
|
||||||
|
# Zakázání ukládání ve hře
|
||||||
|
docker exec -i $CONTAINER rcon-cli save-off
|
||||||
|
docker exec -i $CONTAINER rcon-cli save-all
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
# Vytvoření zálohy
|
||||||
|
tar -czf "$ARCHIVE_NAME" "$WORLD_DIR"
|
||||||
|
|
||||||
|
# Znovupovolení ukládání
|
||||||
|
docker exec -i $CONTAINER rcon-cli save-on
|
||||||
|
|
||||||
|
# Smazání všech záloh ze stejné hodiny, kromě nejnovější
|
||||||
|
find "$BACKUP_DIR" -name "world_${DATE_HOUR}_*.tar.gz" ! -newer "$ARCHIVE_NAME" -delete
|
||||||
|
|
||||||
|
# Zachování pouze nejnovější zálohy z každého předchozího dne
|
||||||
|
find "$BACKUP_DIR" -name "world_*.tar.gz" | while read file; do
|
||||||
|
file_day=$(basename "$file" | cut -d'_' -f2)
|
||||||
|
newest=$(find "$BACKUP_DIR" -name "world_${file_day}_*.tar.gz" | sort | tail -n 1)
|
||||||
|
if [ "$file" != "$newest" ]; then
|
||||||
|
rm "$file"
|
||||||
|
fi
|
||||||
|
done
|
||||||
1
backups/poznamka.md
Normal file
1
backups/poznamka.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
tady se budou nacházet zálohy serveru až se spustí!
|
||||||
5
discord-bot/.env-bot
Normal file
5
discord-bot/.env-bot
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
TOKEN='MTI1ODE0NDgxODk3OTE0Nzg5Ng.GKTl0Q.4vzvSFiPs8tl93B42R7PcqpM70C2Ov0YXHQdVU'
|
||||||
|
GUILD_ID=938745671870185482
|
||||||
|
CHANNEL_ID=1382456524009640057
|
||||||
|
MC_HOST='147.185.221.29'
|
||||||
|
MC_PORT=7272
|
||||||
11
discord-bot/Dockerfile
Normal file
11
discord-bot/Dockerfile
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# discord-bot/Dockerfile
|
||||||
|
FROM python:3.11-slim
|
||||||
|
|
||||||
|
WORKDIR /discord-bot
|
||||||
|
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
CMD ["python", "frankstein-bot.py"]
|
||||||
52
discord-bot/frankstein-bot.py
Normal file
52
discord-bot/frankstein-bot.py
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import discord
|
||||||
|
from discord.ext import tasks, commands
|
||||||
|
from mcstatus import JavaServer
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
TOKEN = os.environ['TOKEN']
|
||||||
|
MC_HOST = os.environ.get('MC_HOST', 'localhost')
|
||||||
|
MC_PORT = int(os.environ.get('MC_PORT', 7272))
|
||||||
|
CHANNEL_ID = int(os.environ['CHANNEL_ID'])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
intents = discord.Intents.default()
|
||||||
|
bot = commands.Bot(command_prefix='!', intents=intents)
|
||||||
|
|
||||||
|
@bot.event
|
||||||
|
async def on_ready():
|
||||||
|
print(f'Přihlášen jako {bot.user}')
|
||||||
|
update_status.start()
|
||||||
|
|
||||||
|
@tasks.loop(seconds=5)
|
||||||
|
async def update_status():
|
||||||
|
channel = bot.get_channel(CHANNEL_ID)
|
||||||
|
if channel is None:
|
||||||
|
print("Kanál nenalezen.")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
server = JavaServer(MC_HOST, MC_PORT)
|
||||||
|
status = server.status()
|
||||||
|
|
||||||
|
player_count = status.players.online
|
||||||
|
name = f'🟢|online|👤:{player_count}'
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print("Server offline nebo nelze připojit:", e)
|
||||||
|
name = '🔴|server down!!!'
|
||||||
|
|
||||||
|
try:
|
||||||
|
if name != channel.name:
|
||||||
|
await channel.edit(name=name)
|
||||||
|
|
||||||
|
|
||||||
|
except discord.Forbidden:
|
||||||
|
|
||||||
|
print("Bot nemá oprávnění měnit název kanálu.")
|
||||||
|
|
||||||
|
except discord.HTTPException as e:
|
||||||
|
print("HTTP chyba:", e)
|
||||||
|
|
||||||
|
bot.run(TOKEN)
|
||||||
3
discord-bot/requirements.txt
Normal file
3
discord-bot/requirements.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
discord.py
|
||||||
|
mcstatus
|
||||||
|
python-dotenv
|
||||||
37
docker-compose.yml
Normal file
37
docker-compose.yml
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
services:
|
||||||
|
mc-vanilla:
|
||||||
|
image: itzg/minecraft-server
|
||||||
|
container_name: mc-vanilla
|
||||||
|
ports:
|
||||||
|
- "25565:25565"
|
||||||
|
environment:
|
||||||
|
TZ: "Europe/Prague"
|
||||||
|
#TYPE: "PAPER"
|
||||||
|
VERSION: "1.21.6"
|
||||||
|
EULA: "TRUE"
|
||||||
|
ENABLE_RCON: "true"
|
||||||
|
RCON_PASSWORD: "Revoluce@1989"
|
||||||
|
RCON_PORT: 25575
|
||||||
|
MAX_PLAYERS: 6
|
||||||
|
VIEW_DISTANCE: 20
|
||||||
|
SIMULATION_DISTANCE: 10
|
||||||
|
OVERRIDE_ICON: true
|
||||||
|
ICON: /icon.png
|
||||||
|
DIFFICULTY: hard
|
||||||
|
MEMORY: 10G
|
||||||
|
INIT_MEMORY: 10G
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- ./data:/data
|
||||||
|
- ./icon.png:/icon.png
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
frankstein-discord-bot:
|
||||||
|
image: python:3.11-slim
|
||||||
|
build:
|
||||||
|
context: ./discord-bot
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
volumes:
|
||||||
|
- ./discord-bot:/discord-bot
|
||||||
|
env_file:
|
||||||
|
- discord-bot/.env-bot
|
||||||
70
minecraft_env_vars.md
Normal file
70
minecraft_env_vars.md
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
|
||||||
|
Minecraft Server Docker Environment Variables (itzg/minecraft-server)
|
||||||
|
=====================================================================
|
||||||
|
|
||||||
|
🧩 Server Configuration
|
||||||
|
-----------------------
|
||||||
|
EULA: Must be set to "TRUE" to accept the Minecraft EULA.
|
||||||
|
VERSION: Specify the Minecraft server version, e.g., "1.20.4".
|
||||||
|
TYPE: Server type, such as "VANILLA", "FORGE", "FABRIC", "PAPER", etc.
|
||||||
|
MOTD: Message of the day displayed in the server list.
|
||||||
|
DIFFICULTY: Game difficulty; options: "peaceful", "easy", "normal", "hard".
|
||||||
|
MAX_PLAYERS: Max number of players allowed.
|
||||||
|
VIEW_DISTANCE: Number of chunks sent to players around them.
|
||||||
|
ALLOW_NETHER: Enable or disable the Nether.
|
||||||
|
ENABLE_COMMAND_BLOCK: Enable or disable command blocks.
|
||||||
|
FORCE_GAMEMODE: Force players to join in the default game mode.
|
||||||
|
GENERATE_STRUCTURES: Enable or disable structure generation.
|
||||||
|
HARDCORE: Enable or disable hardcore mode.
|
||||||
|
MAX_BUILD_HEIGHT: Max build height.
|
||||||
|
SPAWN_ANIMALS: Enable or disable animal spawning.
|
||||||
|
SPAWN_MONSTERS: Enable or disable monster spawning.
|
||||||
|
SPAWN_NPCS: Enable or disable NPC spawning.
|
||||||
|
SPAWN_PROTECTION: Radius of spawn protection for non-ops.
|
||||||
|
LEVEL_NAME: Name of the world folder.
|
||||||
|
LEVEL_TYPE: "DEFAULT", "FLAT", "LARGEBIOMES", "AMPLIFIED", "CUSTOMIZED".
|
||||||
|
LEVEL_SEED: World seed.
|
||||||
|
PVP: Enable or disable player combat.
|
||||||
|
ONLINE_MODE: Enable/disable Mojang authentication.
|
||||||
|
ALLOW_FLIGHT: Allow/disallow flight.
|
||||||
|
|
||||||
|
🛡️ Access Control
|
||||||
|
-----------------
|
||||||
|
WHITELIST: Comma-separated list of usernames.
|
||||||
|
OPS: Comma-separated list of operators.
|
||||||
|
ENABLE_WHITELIST: Enable/disable whitelist.
|
||||||
|
ENFORCE_WHITELIST: Always enforce whitelist.
|
||||||
|
|
||||||
|
⚙️ Advanced Settings
|
||||||
|
--------------------
|
||||||
|
ICON: URL or file path to server icon.
|
||||||
|
OVERRIDE_ICON: TRUE to override existing icon.
|
||||||
|
ENABLE_RCON: Enable/disable RCON.
|
||||||
|
RCON_PASSWORD: RCON password.
|
||||||
|
RCON_PORT: Default is 25575.
|
||||||
|
ENABLE_QUERY: Enable/disable GameSpy4 query.
|
||||||
|
QUERY_PORT: Default is 25565.
|
||||||
|
ENABLE_JMX: Enable/disable JMX.
|
||||||
|
JMX_PORT: Default is 7091.
|
||||||
|
USE_AIKAR_FLAGS: Use Aikar's JVM flags.
|
||||||
|
JVM_OPTS, JVM_XX_OPTS, JVM_DD_OPTS: JVM tuning.
|
||||||
|
EXTRA_ARGS: Extra server args.
|
||||||
|
LOG_TIMESTAMP: Include timestamps in logs.
|
||||||
|
ENABLE_ROLLING_LOGS: Enable rolling logs.
|
||||||
|
|
||||||
|
🧪 Experimental/Modding
|
||||||
|
------------------------
|
||||||
|
MODPACK, MODPACK_VERSION: Modpack configs.
|
||||||
|
MODRINTH_PROJECT, MODRINTH_VERSION: Modrinth config.
|
||||||
|
CURSEFORGE_PROJECT, CURSEFORGE_FILE_ID: CurseForge config.
|
||||||
|
AUTODOWNLOAD: Automatically download mods.
|
||||||
|
|
||||||
|
🕒 Time and Locale
|
||||||
|
------------------
|
||||||
|
TZ: Timezone, e.g., "Europe/Prague".
|
||||||
|
|
||||||
|
🧰 Custom Properties
|
||||||
|
--------------------
|
||||||
|
CUSTOM_SERVER_PROPERTIES: Newline-separated key=value for custom settings.
|
||||||
|
|
||||||
|
See: https://github.com/itzg/docker-minecraft-server
|
||||||
8
restart.sh
Normal file
8
restart.sh
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
SERVICE_NAME="mc-vanilla"
|
||||||
|
|
||||||
|
echo "🔄 Restartuji server..."
|
||||||
|
docker compose up -d --force-recreate --build "$SERVICE_NAME"
|
||||||
|
|
||||||
|
|
||||||
34
restore.sh
Normal file
34
restore.sh
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
#relative path
|
||||||
|
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
|
|
||||||
|
CONTAINER="mc-vanilla"
|
||||||
|
BACKUP_DIR="/mnt/backups/minecraft_backups/frankstein"
|
||||||
|
WORLD_DIR="$DIR/data/world"
|
||||||
|
|
||||||
|
mapfile -t BACKUPS < <(ls -1t "$BACKUP_DIR"/world_*.tar.gz)
|
||||||
|
if [ ${#BACKUPS[@]} -eq 0 ]; then
|
||||||
|
echo "❌ Žádné zálohy nenalezeny!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "📦 Dostupné zálohy:"
|
||||||
|
for i in "${!BACKUPS[@]}"; do
|
||||||
|
echo "[$i] ${BACKUPS[$i]}"
|
||||||
|
done
|
||||||
|
|
||||||
|
read -p "🔁 Zadej číslo zálohy: " INDEX
|
||||||
|
SELECTED="${BACKUPS[$INDEX]}"
|
||||||
|
[ -z "$SELECTED" ] && echo "❌ Neplatný výběr." && exit 1
|
||||||
|
|
||||||
|
read -p "⚠️ Přepsat svět? (y/N): " CONFIRM
|
||||||
|
[[ "$CONFIRM" != "y" && "$CONFIRM" != "Y" ]] && exit 0
|
||||||
|
|
||||||
|
docker compose stop "$CONTAINER"
|
||||||
|
rm -rf "$WORLD_DIR"
|
||||||
|
tar -xzf "$SELECTED" -C .
|
||||||
|
|
||||||
|
read -p "▶️ Spustit server? (y/N): " AUTOSTART
|
||||||
|
[[ "$AUTOSTART" == "y" || "$AUTOSTART" == "Y" ]] && docker compose up -d --force-recreate "$CONTAINER"
|
||||||
10
start.sh
Normal file
10
start.sh
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
SERVICE_NAME="mc-vanilla"
|
||||||
|
|
||||||
|
if docker ps --format '{{.Names}}' | grep -q "$SERVICE_NAME"; then
|
||||||
|
echo "✅ Server už běží."
|
||||||
|
else
|
||||||
|
echo "▶️ Spouštím server..."
|
||||||
|
docker compose up -d --force-recreate "$SERVICE_NAME"
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user